From 21be41c2a9e354fc55b723effa4bb8fb9fd9593f Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sun, 30 Mar 2025 17:56:59 +0900 Subject: [PATCH] fix(Reddit - Disable screenshot popup): Screenshot popup not being completely removed https://github.com/inotia00/ReVanced_Extended/issues/1810 --- .../layout/screenshotpopup/Fingerprints.kt | 37 ++------ .../screenshotpopup/ScreenshotPopupPatch.kt | 95 ++++++++++++++----- .../utils/resourceid/SharedResourceIdPatch.kt | 19 ---- 3 files changed, 77 insertions(+), 74 deletions(-) delete mode 100644 patches/src/main/kotlin/app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatch.kt diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/Fingerprints.kt index 13cc83e84..01f630b2b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/Fingerprints.kt @@ -1,36 +1,15 @@ package app.revanced.patches.reddit.layout.screenshotpopup -import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner -import app.revanced.util.containsLiteralInstruction import app.revanced.util.fingerprint.legacyFingerprint -import com.android.tools.smali.dexlib2.Opcode +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags -/** - * Reddit 2025.06.0 ~ - */ -internal val screenshotTakenBannerFingerprint = legacyFingerprint( +internal val screenshotBannerContainerFingerprint = legacyFingerprint( name = "screenshotTakenBannerFingerprint", - returnType = "L", - opcodes = listOf( - Opcode.CONST_4, - Opcode.IF_NE, - ), - customFingerprint = { method, classDef -> - method.containsLiteralInstruction(screenShotShareBanner) && - classDef.type.startsWith("Lcom/reddit/sharing/screenshot/composables/") && - method.name == "invoke" - } -) - -/** - * ~ Reddit 2025.05.1 - */ -internal val screenshotTakenBannerLegacyFingerprint = legacyFingerprint( - name = "screenshotTakenBannerLegacyFingerprint", returnType = "V", - parameters = listOf("Landroidx/compose/runtime/", "I"), - customFingerprint = { method, classDef -> - classDef.type.endsWith("\$ScreenshotTakenBannerKt\$lambda-1\$1;") && - method.name == "invoke" - } + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf( + "bannerContainer", + "scope", + ) ) diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/ScreenshotPopupPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/ScreenshotPopupPatch.kt index a8ceffdb9..4de050ce9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/ScreenshotPopupPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/screenshotpopup/ScreenshotPopupPatch.kt @@ -2,22 +2,26 @@ package app.revanced.patches.reddit.layout.screenshotpopup import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH import app.revanced.patches.reddit.utils.patch.PatchList.DISABLE_SCREENSHOT_POPUP -import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner -import app.revanced.patches.reddit.utils.resourceid.sharedResourceIdPatch -import app.revanced.patches.reddit.utils.settings.is_2025_06_or_greater import app.revanced.patches.reddit.utils.settings.settingsPatch import app.revanced.patches.reddit.utils.settings.updatePatchStatus +import app.revanced.util.findMutableMethodOf +import app.revanced.util.fingerprint.methodCall import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstInstructionReversedOrThrow -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow +import app.revanced.util.indexOfFirstStringInstruction import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference private const val EXTENSION_METHOD_DESCRIPTOR = "$PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup()Z" @@ -29,41 +33,80 @@ val screenshotPopupPatch = bytecodePatch( ) { compatibleWith(COMPATIBLE_PACKAGE) - dependsOn( - settingsPatch, - sharedResourceIdPatch, - ) + dependsOn(settingsPatch) execute { - if (is_2025_06_or_greater) { - screenshotTakenBannerFingerprint.methodOrThrow().apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(screenShotShareBanner) - val insertIndex = indexOfFirstInstructionReversedOrThrow(literalIndex, Opcode.CONST_4) - val insertRegister = getInstruction(insertIndex).registerA - val jumpIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.SGET_OBJECT) + val screenshotTriggerSharingListenerMethodCall = + screenshotBannerContainerFingerprint.methodCall() - addInstructionsWithLabels( - insertIndex, """ - invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR - move-result v$insertRegister - if-nez v$insertRegister, :hidden - """, ExternalLabel("hidden", getInstruction(jumpIndex)) - ) + fun indexOfScreenshotTriggerInstruction(method: Method) = + method.indexOfFirstInstruction { + getReference()?.toString() == screenshotTriggerSharingListenerMethodCall } - } else { - screenshotTakenBannerLegacyFingerprint.methodOrThrow().apply { + + val isScreenshotTriggerMethod: Method.() -> Boolean = { + indexOfScreenshotTriggerInstruction(this) >= 0 + } + + var hookCount = 0 + + fun MutableMethod.hook() { + if (returnType == "V") { addInstructionsWithLabels( 0, """ invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR move-result v0 - if-eqz v0, :dismiss + if-eqz v0, :shown return-void - """, ExternalLabel("dismiss", getInstruction(0)) + """, ExternalLabel("shown", getInstruction(0)) ) + + hookCount++ + } else if (returnType.startsWith("L")) { // Reddit 2025.06+ + val insertIndex = + indexOfFirstStringInstruction("screenshotTriggerSharingListener") + + if (insertIndex >= 0) { + val insertRegister = + getInstruction(insertIndex).registerA + val triggerIndex = + indexOfScreenshotTriggerInstruction(this) + val jumpIndex = + indexOfFirstInstructionOrThrow(triggerIndex, Opcode.RETURN_OBJECT) + + addInstructionsWithLabels( + insertIndex, """ + invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR + move-result v$insertRegister + if-nez v$insertRegister, :hidden + """, ExternalLabel("hidden", getInstruction(jumpIndex)) + ) + + hookCount++ + } } } + screenshotBannerContainerFingerprint + .methodOrThrow() + .hook() + + classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (method.isScreenshotTriggerMethod()) { + proxy(classDef) + .mutableClass + .findMutableMethodOf(method) + .hook() + } + } + } + + if (hookCount == 0) { + throw PatchException("Failed to find hook method") + } + updatePatchStatus( "enableScreenshotPopup", DISABLE_SCREENSHOT_POPUP diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatch.kt deleted file mode 100644 index 4f8faec53..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatch.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.reddit.utils.resourceid - -import app.revanced.patcher.patch.resourcePatch -import app.revanced.patches.shared.mapping.ResourceType.STRING -import app.revanced.patches.shared.mapping.getResourceId -import app.revanced.patches.shared.mapping.resourceMappingPatch - -var screenShotShareBanner = -1L - private set - -internal val sharedResourceIdPatch = resourcePatch( - description = "sharedResourceIdPatch" -) { - dependsOn(resourceMappingPatch) - - execute { - screenShotShareBanner = getResourceId(STRING, "screenshot_share_banner_title") - } -} \ No newline at end of file