fix(Reddit - Disable screenshot popup): Screenshot popup not being completely removed https://github.com/inotia00/ReVanced_Extended/issues/1810

This commit is contained in:
inotia00 2025-04-01 18:51:58 +09:00
parent 15db05c636
commit bb5964ce98
4 changed files with 42 additions and 182 deletions

View File

@ -5,7 +5,7 @@ import app.revanced.extension.reddit.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ScreenshotPopupPatch { public class ScreenshotPopupPatch {
public static boolean disableScreenshotPopup() { public static Boolean disableScreenshotPopup(Boolean original) {
return Settings.DISABLE_SCREENSHOT_POPUP.get(); return Settings.DISABLE_SCREENSHOT_POPUP.get() ? Boolean.FALSE : original;
} }
} }

View File

@ -1,60 +0,0 @@
package app.revanced.patches.reddit.layout.screenshotpopup
import app.revanced.patches.reddit.utils.resourceid.actionShare
import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
internal val screenshotBannerContainerFingerprint = legacyFingerprint(
name = "screenshotTakenBannerFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf(
"bannerContainer",
"scope",
)
)
/**
* Reddit 2025.06.0 ~
*/
internal val screenshotTakenBannerComposableFingerprint = legacyFingerprint(
name = "screenshotTakenBannerComposableFingerprint",
returnType = "L",
customFingerprint = { method, classDef ->
method.containsLiteralInstruction(actionShare) &&
method.containsLiteralInstruction(screenShotShareBanner) &&
classDef.type.startsWith("Lcom/reddit/sharing/screenshot/composables/") &&
method.name == "invoke"
}
)
/**
* ~ Reddit 2025.05.1
*/
internal val screenshotTakenBannerLambdaActionFingerprint = legacyFingerprint(
name = "screenshotTakenBannerLambdaFingerprint",
returnType = "V",
parameters = listOf("Landroidx/compose/runtime/", "I"),
customFingerprint = { method, _ ->
method.containsLiteralInstruction(actionShare) &&
method.name == "invoke"
}
)
/**
* ~ Reddit 2025.05.1
*/
internal val screenshotTakenBannerLambdaBannerFingerprint = legacyFingerprint(
name = "screenshotTakenBannerLambdaFingerprint",
returnType = "V",
parameters = listOf("Landroidx/compose/runtime/", "I"),
customFingerprint = { method, _ ->
method.containsLiteralInstruction(screenShotShareBanner) &&
method.name == "invoke"
}
)

View File

@ -1,37 +1,22 @@
package app.revanced.patches.reddit.layout.screenshotpopup package app.revanced.patches.reddit.layout.screenshotpopup
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch 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.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH 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.patch.PatchList.DISABLE_SCREENSHOT_POPUP
import app.revanced.patches.reddit.utils.resourceid.actionShare
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.settingsPatch
import app.revanced.patches.reddit.utils.settings.updatePatchStatus import app.revanced.patches.reddit.utils.settings.updatePatchStatus
import app.revanced.util.findMutableMethodOf 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.getReference
import app.revanced.util.indexOfFirstInstruction 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.Opcode
import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_METHOD_DESCRIPTOR =
"$PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup()Z"
@Suppress("unused") @Suppress("unused")
val screenshotPopupPatch = bytecodePatch( val screenshotPopupPatch = bytecodePatch(
DISABLE_SCREENSHOT_POPUP.title, DISABLE_SCREENSHOT_POPUP.title,
@ -39,121 +24,62 @@ val screenshotPopupPatch = bytecodePatch(
) { ) {
compatibleWith(COMPATIBLE_PACKAGE) compatibleWith(COMPATIBLE_PACKAGE)
dependsOn( dependsOn(settingsPatch)
settingsPatch,
sharedResourceIdPatch,
)
execute { execute {
val screenshotTriggerSharingListenerMethodCall = fun indexOfShowBannerInstruction(method: Method) =
screenshotBannerContainerFingerprint.methodCall()
fun indexOfScreenshotTriggerInstruction(method: Method) =
method.indexOfFirstInstruction { method.indexOfFirstInstruction {
getReference<MethodReference>()?.toString() == screenshotTriggerSharingListenerMethodCall val reference = getReference<FieldReference>()
opcode == Opcode.IGET_OBJECT &&
reference?.name?.contains("shouldShowBanner") == true &&
reference.definingClass.startsWith("Lcom/reddit/sharing/screenshot/") == true
} }
val isScreenshotTriggerMethod: Method.() -> Boolean = { fun indexOfSetValueInstruction(method: Method) =
indexOfScreenshotTriggerInstruction(this) >= 0 method.indexOfFirstInstruction {
} getReference<MethodReference>()?.name == "setValue"
var hookCount = 0
fun MutableMethod.hook() {
if (returnType == "V") {
addInstructionsWithLabels(
0, """
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
move-result v0
if-eqz v0, :shown
return-void
""", ExternalLabel("shown", getInstruction(0))
)
hookCount++
} else if (returnType.startsWith("L")) { // Reddit 2025.06+
val insertIndex =
indexOfFirstStringInstruction("screenshotTriggerSharingListener")
if (insertIndex >= 0) {
val insertRegister =
getInstruction<OneRegisterInstruction>(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 fun indexOfBooleanInstruction(method: Method, startIndex: Int = 0) =
.methodOrThrow() method.indexOfFirstInstruction(startIndex) {
.hook() val reference = getReference<FieldReference>()
opcode == Opcode.SGET_OBJECT &&
reference?.definingClass == "Ljava/lang/Boolean;" &&
reference.type == "Ljava/lang/Boolean;"
}
val isScreenShotMethod: Method.() -> Boolean = {
definingClass.startsWith("Lcom/reddit/sharing/screenshot/") &&
name == "invokeSuspend" &&
indexOfShowBannerInstruction(this) >= 0 &&
indexOfBooleanInstruction(this) >= 0 &&
indexOfSetValueInstruction(this) >= 0
}
classes.forEach { classDef -> classes.forEach { classDef ->
classDef.methods.forEach { method -> classDef.methods.forEach { method ->
if (method.isScreenshotTriggerMethod()) { if (method.isScreenShotMethod()) {
proxy(classDef) proxy(classDef)
.mutableClass .mutableClass
.findMutableMethodOf(method) .findMutableMethodOf(method)
.hook() .apply {
val showBannerIndex = indexOfShowBannerInstruction(this)
val booleanIndex = indexOfBooleanInstruction(this, showBannerIndex)
val booleanRegister =
getInstruction<OneRegisterInstruction>(booleanIndex).registerA
addInstructions(
booleanIndex + 1, """
invoke-static {v$booleanRegister}, $PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup(Ljava/lang/Boolean;)Ljava/lang/Boolean;
move-result-object v$booleanRegister
"""
)
}
} }
} }
} }
if (hookCount == 0) {
throw PatchException("Failed to find hook method")
}
if (is_2025_06_or_greater) {
screenshotTakenBannerComposableFingerprint.methodOrThrow().apply {
arrayOf(
actionShare,
screenShotShareBanner
).forEach { literal ->
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal)
val insertIndex = indexOfFirstInstructionReversedOrThrow(literalIndex, Opcode.CONST_4)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
val jumpIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.SGET_OBJECT)
addInstructionsWithLabels(
insertIndex, """
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
move-result v$insertRegister
if-nez v$insertRegister, :hidden
""", ExternalLabel("hidden", getInstruction(jumpIndex))
)
}
}
} else {
arrayOf(
screenshotTakenBannerLambdaActionFingerprint,
screenshotTakenBannerLambdaBannerFingerprint
).forEach { fingerprint ->
fingerprint.methodOrThrow().addInstructionsWithLabels(
0, """
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
move-result v0
if-eqz v0, :ignore
return-void
:ignore
nop
"""
)
}
}
updatePatchStatus( updatePatchStatus(
"enableScreenshotPopup", "enableScreenshotPopup",
DISABLE_SCREENSHOT_POPUP DISABLE_SCREENSHOT_POPUP

View File

@ -5,12 +5,8 @@ import app.revanced.patches.shared.mapping.ResourceType.STRING
import app.revanced.patches.shared.mapping.getResourceId import app.revanced.patches.shared.mapping.getResourceId
import app.revanced.patches.shared.mapping.resourceMappingPatch import app.revanced.patches.shared.mapping.resourceMappingPatch
var actionShare = -1L
private set
var nsfwDialogTitle = -1L var nsfwDialogTitle = -1L
private set private set
var screenShotShareBanner = -1L
private set
internal val sharedResourceIdPatch = resourcePatch( internal val sharedResourceIdPatch = resourcePatch(
description = "sharedResourceIdPatch" description = "sharedResourceIdPatch"
@ -18,8 +14,6 @@ internal val sharedResourceIdPatch = resourcePatch(
dependsOn(resourceMappingPatch) dependsOn(resourceMappingPatch)
execute { execute {
actionShare = getResourceId(STRING, "action_share")
nsfwDialogTitle = getResourceId(STRING, "nsfw_dialog_title") nsfwDialogTitle = getResourceId(STRING, "nsfw_dialog_title")
screenShotShareBanner = getResourceId(STRING, "screenshot_share_banner_title")
} }
} }