diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/OnBackPressedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/OnBackPressedFingerprint.kt new file mode 100644 index 000000000..6b2b7e4e4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/OnBackPressedFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object OnBackPressedFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.RETURN_VOID + ), + customFingerprint = { methodDef -> + methodDef.definingClass.endsWith("WatchWhileActivity;") + && methodDef.name == "onBackPressed" + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollPositionFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollPositionFingerprint.kt index 3647ab2e1..6a02800f5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollPositionFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint +package app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopFingerprint.kt new file mode 100644 index 000000000..4af17a7c5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ScrollTopFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.CHECK_CAST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.GOTO, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE + ) +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopParentFingerprint.kt new file mode 100644 index 000000000..faafb6de2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/fingerprint/ScrollTopParentFingerprint.kt @@ -0,0 +1,26 @@ +package app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ScrollTopParentFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + parameters = listOf("L", "L", "L", "L"), + opcodes = listOf( + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST_16, + Opcode.INVOKE_VIRTUAL, + Opcode.NEW_INSTANCE + ), + customFingerprint = { methodDef -> + methodDef.name == "" + } +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/patch/DoubleBackToClosePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/patch/DoubleBackToClosePatch.kt new file mode 100644 index 000000000..0c64df933 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoclose/patch/DoubleBackToClosePatch.kt @@ -0,0 +1,100 @@ +package app.revanced.patches.youtube.misc.doublebacktoclose.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint.OnBackPressedFingerprint +import app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint.ScrollPositionFingerprint +import app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint.ScrollTopFingerprint +import app.revanced.patches.youtube.misc.doublebacktoclose.fingerprint.ScrollTopParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.toErrorResult +import app.revanced.shared.patches.gestures.PredictiveBackGesturePatch +import app.revanced.shared.util.integrations.Constants.UTILS_PATH + +@Patch +@Name("double-back-to-close") +@DependsOn([PredictiveBackGesturePatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class DoubleBackToClosePatch : BytecodePatch( + listOf( + OnBackPressedFingerprint, + ScrollPositionFingerprint, + ScrollTopParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + /* + Hook onBackPressed method inside WatchWhileActivity + */ + OnBackPressedFingerprint.result?.let { result -> + val insertIndex = result.scanResult.patternScanResult!!.endIndex + + with(result.mutableMethod) { + addInstruction( + insertIndex, + "invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR" + + "->" + + "closeActivityOnBackPressed(Lcom/google/android/apps/youtube/app/watchwhile/WatchWhileActivity;)V" + ) + } + } ?: return OnBackPressedFingerprint.toErrorResult() + + + /* + Inject the methods which start of ScrollView + */ + ScrollPositionFingerprint.result?.let { result -> + val insertMethod = context.toMethodWalker(result.method) + .nextMethod(result.scanResult.patternScanResult!!.startIndex + 1, true) + .getMethod() as MutableMethod + + val insertIndex = insertMethod.implementation!!.instructions.size - 1 - 1 + + injectScrollView(insertMethod, insertIndex, "onStartScrollView") + } ?: return ScrollPositionFingerprint.toErrorResult() + + + /* + Inject the methods which stop of ScrollView + */ + ScrollTopParentFingerprint.result?.let { parentResult -> + ScrollTopFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result -> + val insertMethod = result.mutableMethod + val insertIndex = result.scanResult.patternScanResult!!.endIndex + + injectScrollView(insertMethod, insertIndex, "onStopScrollView") + } ?: return ScrollTopFingerprint.toErrorResult() + } ?: return ScrollTopParentFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = + "$UTILS_PATH/DoubleBackToClosePatch;" + + fun injectScrollView( + method: MutableMethod, + index: Int, + descriptor: String + ) { + method.addInstruction( + index, + "invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->$descriptor()V" + ) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt deleted file mode 100644 index 99266d540..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object RecyclerViewFingerprint : MethodFingerprint( - returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("I"), - opcodes = listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - ), - strings = listOf("Cannot scroll to position a LayoutManager set. Call setLayoutManager with a non-null argument."), - customFingerprint = { methodDef -> - methodDef.definingClass == "Landroid/support/v7/widget/RecyclerView;" - } -) - diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt deleted file mode 100644 index c167d70ef..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt +++ /dev/null @@ -1,68 +0,0 @@ -package app.revanced.patches.youtube.misc.doublebacktoexit.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint.RecyclerViewFingerprint -import app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint.ScrollPositionFingerprint -import app.revanced.shared.annotation.YouTubeCompatibility -import app.revanced.shared.extensions.toErrorResult -import app.revanced.shared.patches.gestures.PredictiveBackGesturePatch -import app.revanced.shared.util.bytecode.BytecodeHelper -import app.revanced.shared.util.integrations.Constants.UTILS_PATH -import org.jf.dexlib2.Opcode - -@Name("enable-double-back-to-exit") -@Description("Enable double back to exit.") -@YouTubeCompatibility -@Version("0.0.1") -@DependsOn([PredictiveBackGesturePatch::class]) -class DoubleBackToExitPatch : BytecodePatch( - listOf( - RecyclerViewFingerprint, - ScrollPositionFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val DTE_CLASS_DESCRIPTOR = "$UTILS_PATH/DoubleBackToExitPatch;" - - val scrollPositionResult = ScrollPositionFingerprint.result!! - val scrollPositionMethod = - context.toMethodWalker(scrollPositionResult.method) - .nextMethod(scrollPositionResult.scanResult.patternScanResult!!.startIndex + 1, true) - .getMethod() as MutableMethod - val backToExitInstructions = scrollPositionMethod.implementation!!.instructions - - for ((index, instruction) in backToExitInstructions.withIndex()) { - if (instruction.opcode != Opcode.CONST_4) continue - - scrollPositionMethod.addInstruction( - index + 2, - "invoke-static {}, $DTE_CLASS_DESCRIPTOR->onCreate()V" - ) - - break - } - - val recyclerViewResult = RecyclerViewFingerprint.result ?: return RecyclerViewFingerprint.toErrorResult() - val recyclerViewMethod = recyclerViewResult.mutableMethod - val recyclerViewEndIndex = recyclerViewResult.scanResult.patternScanResult!!.endIndex - - recyclerViewMethod.addInstruction( - recyclerViewEndIndex, - "invoke-static {}, $DTE_CLASS_DESCRIPTOR->onDestroy()V" - ) - - BytecodeHelper.injectBackPressed(context) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt index edb1df8f3..150e2e67c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt @@ -9,7 +9,7 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.misc.doublebacktoexit.patch.DoubleBackToExitPatch +import app.revanced.patches.youtube.misc.doublebacktoclose.patch.DoubleBackToClosePatch import app.revanced.patches.youtube.misc.litho.filter.fingerprints.LithoFingerprint import app.revanced.patches.youtube.misc.swiperefresh.patch.SwipeRefreshPatch import app.revanced.shared.annotation.YouTubeCompatibility @@ -22,7 +22,7 @@ import org.jf.dexlib2.Opcode @DependsOn( [ - DoubleBackToExitPatch::class, + DoubleBackToClosePatch::class, SwipeRefreshPatch::class ] ) diff --git a/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt b/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt index 4d491d998..2d1989026 100644 --- a/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt +++ b/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt @@ -28,32 +28,6 @@ internal object BytecodeHelper { } } - fun injectBackPressed( - context: BytecodeContext - ) { - context.classes.forEach { classDef -> - classDef.methods.forEach { method -> - if (classDef.type.endsWith("WatchWhileActivity;") && method.name == "onBackPressed") { - val onBackPressedMethod = - context.proxy(classDef).mutableClass.methods.first { it.name == "onBackPressed" } - - val onBackPressedMethodInstructions = - onBackPressedMethod.implementation!!.instructions - - for ((index, instruction) in onBackPressedMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.RETURN_VOID) continue - - onBackPressedMethod.addInstruction( - index, - "invoke-static {p0}, $UTILS_PATH/DoubleBackToExitPatch;->doubleBackToExit(Lcom/google/android/apps/youtube/app/watchwhile/WatchWhileActivity;)V" - ) - break - } - } - } - } - } - fun patchStatus( context: BytecodeContext, name: String