mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-17 14:42:26 +01:00
feat(YouTube Music): Add Enable debugging patch (#5939)
This commit is contained in:
committed by
GitHub
parent
e26c971067
commit
418f5945c2
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.extension.youtube.patches;
|
package app.revanced.extension.shared.patches;
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
@@ -401,6 +401,10 @@ public final class app/revanced/patches/music/misc/backgroundplayback/Background
|
|||||||
public static final fun getBackgroundPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getBackgroundPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/misc/debugging/EnableDebuggingPatchKt {
|
||||||
|
public static final fun getEnableDebuggingPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/misc/extension/SharedExtensionPatchKt {
|
public final class app/revanced/patches/music/misc/extension/SharedExtensionPatchKt {
|
||||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.music.misc.debugging
|
||||||
|
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.debugging.enableDebuggingPatch
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val enableDebuggingPatch = enableDebuggingPatch(
|
||||||
|
block = {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
compatibleWith(
|
||||||
|
"com.google.android.apps.youtube.music"(
|
||||||
|
"7.29.52"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// String feature flag does not appear to be present with YT Music.
|
||||||
|
hookStringFeatureFlag = false,
|
||||||
|
preferenceScreen = PreferenceScreen.MISC
|
||||||
|
)
|
||||||
@@ -8,12 +8,16 @@ import app.revanced.patches.all.misc.resources.addResources
|
|||||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.*
|
import app.revanced.patches.shared.misc.settings.preference.BasePreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
|
||||||
import app.revanced.patches.shared.misc.settings.settingsPatch
|
import app.revanced.patches.shared.misc.settings.settingsPatch
|
||||||
import app.revanced.util.*
|
import app.revanced.util.ResourceGroup
|
||||||
|
import app.revanced.util.copyResources
|
||||||
|
import app.revanced.util.copyXmlNode
|
||||||
|
import app.revanced.util.inputStreamFromBundledResource
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||||
@@ -23,7 +27,6 @@ private const val GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
|||||||
|
|
||||||
private val preferences = mutableSetOf<BasePreference>()
|
private val preferences = mutableSetOf<BasePreference>()
|
||||||
|
|
||||||
|
|
||||||
private val settingsResourcePatch = resourcePatch {
|
private val settingsResourcePatch = resourcePatch {
|
||||||
dependsOn(
|
dependsOn(
|
||||||
resourceMappingPatch,
|
resourceMappingPatch,
|
||||||
@@ -87,27 +90,6 @@ val settingsPatch = bytecodePatch(
|
|||||||
addResources("music", "misc.settings.settingsPatch")
|
addResources("music", "misc.settings.settingsPatch")
|
||||||
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||||
|
|
||||||
// Should make a separate debugging patch, but for now include it with all installations.
|
|
||||||
PreferenceScreen.MISC.addPreferences(
|
|
||||||
PreferenceScreenPreference(
|
|
||||||
key = "revanced_debug_screen",
|
|
||||||
sorting = Sorting.UNSORTED,
|
|
||||||
preferences = setOf(
|
|
||||||
SwitchPreference("revanced_debug"),
|
|
||||||
NonInteractivePreference(
|
|
||||||
"revanced_debug_export_logs_to_clipboard",
|
|
||||||
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
|
||||||
selectable = true
|
|
||||||
),
|
|
||||||
NonInteractivePreference(
|
|
||||||
"revanced_debug_logs_clear_buffer",
|
|
||||||
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
|
||||||
selectable = true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add an "About" preference to the top.
|
// Add an "About" preference to the top.
|
||||||
preferences += NonInteractivePreference(
|
preferences += NonInteractivePreference(
|
||||||
key = "revanced_settings_music_screen_0_about",
|
key = "revanced_settings_music_screen_0_about",
|
||||||
@@ -154,19 +136,19 @@ fun newIntent(settingsName: String) = IntentPreference.Intent(
|
|||||||
|
|
||||||
object PreferenceScreen : BasePreferenceScreen() {
|
object PreferenceScreen : BasePreferenceScreen() {
|
||||||
val ADS = Screen(
|
val ADS = Screen(
|
||||||
"revanced_settings_music_screen_1_ads",
|
key = "revanced_settings_music_screen_1_ads",
|
||||||
summaryKey = null
|
summaryKey = null
|
||||||
)
|
)
|
||||||
val GENERAL = Screen(
|
val GENERAL = Screen(
|
||||||
"revanced_settings_music_screen_2_general",
|
key = "revanced_settings_music_screen_2_general",
|
||||||
summaryKey = null
|
summaryKey = null
|
||||||
)
|
)
|
||||||
val PLAYER = Screen(
|
val PLAYER = Screen(
|
||||||
"revanced_settings_music_screen_3_player",
|
key = "revanced_settings_music_screen_3_player",
|
||||||
summaryKey = null
|
summaryKey = null
|
||||||
)
|
)
|
||||||
val MISC = Screen(
|
val MISC = Screen(
|
||||||
"revanced_settings_music_screen_4_misc",
|
key = "revanced_settings_music_screen_4_misc",
|
||||||
summaryKey = null
|
summaryKey = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package app.revanced.patches.shared.misc.debugging
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchBuilder
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.BasePreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/shared/patches/EnableDebuggingPatch;"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch shared with YouTube and YT Music.
|
||||||
|
*/
|
||||||
|
internal fun enableDebuggingPatch(
|
||||||
|
block: BytecodePatchBuilder.() -> Unit = {},
|
||||||
|
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||||
|
hookStringFeatureFlag: Boolean,
|
||||||
|
preferenceScreen: BasePreferenceScreen.Screen,
|
||||||
|
additionalDebugPreferences: List<BasePreference> = emptyList()
|
||||||
|
) = bytecodePatch(
|
||||||
|
name = "Enable debugging",
|
||||||
|
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
|
||||||
|
) {
|
||||||
|
|
||||||
|
dependsOn(addResourcesPatch)
|
||||||
|
|
||||||
|
block()
|
||||||
|
|
||||||
|
execute {
|
||||||
|
executeBlock()
|
||||||
|
|
||||||
|
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||||
|
|
||||||
|
val preferences = mutableSetOf<BasePreference>(
|
||||||
|
SwitchPreference("revanced_debug"),
|
||||||
|
)
|
||||||
|
|
||||||
|
preferences.addAll(additionalDebugPreferences)
|
||||||
|
|
||||||
|
preferences.addAll(
|
||||||
|
listOf(
|
||||||
|
SwitchPreference("revanced_debug_stacktrace"),
|
||||||
|
SwitchPreference("revanced_debug_toast_on_error"),
|
||||||
|
NonInteractivePreference(
|
||||||
|
"revanced_debug_export_logs_to_clipboard",
|
||||||
|
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
||||||
|
selectable = true
|
||||||
|
),
|
||||||
|
NonInteractivePreference(
|
||||||
|
"revanced_debug_logs_clear_buffer",
|
||||||
|
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
||||||
|
selectable = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
preferenceScreen.addPreferences(
|
||||||
|
PreferenceScreenPreference(
|
||||||
|
key = "revanced_debug_screen",
|
||||||
|
sorting = Sorting.UNSORTED,
|
||||||
|
preferences = preferences,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hook the methods that look up if a feature flag is active.
|
||||||
|
experimentalBooleanFeatureFlagFingerprint.match(
|
||||||
|
experimentalFeatureFlagParentFingerprint.originalClassDef
|
||||||
|
).method.apply {
|
||||||
|
findInstructionIndicesReversedOrThrow(Opcode.RETURN).forEach { index ->
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
index,
|
||||||
|
"""
|
||||||
|
invoke-static { v$register, p1 }, $EXTENSION_CLASS_DESCRIPTOR->isBooleanFeatureFlagEnabled(ZLjava/lang/Long;)Z
|
||||||
|
move-result v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
experimentalDoubleFeatureFlagFingerprint.match(
|
||||||
|
experimentalFeatureFlagParentFingerprint.originalClassDef
|
||||||
|
).method.apply {
|
||||||
|
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
|
||||||
|
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isDoubleFeatureFlagEnabled(DJD)D
|
||||||
|
move-result-wide v0
|
||||||
|
return-wide v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
experimentalLongFeatureFlagFingerprint.match(
|
||||||
|
experimentalFeatureFlagParentFingerprint.originalClassDef
|
||||||
|
).method.apply {
|
||||||
|
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
move-result-wide v0
|
||||||
|
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isLongFeatureFlagEnabled(JJJ)J
|
||||||
|
move-result-wide v0
|
||||||
|
return-wide v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hookStringFeatureFlag) experimentalStringFeatureFlagFingerprint.match(
|
||||||
|
experimentalFeatureFlagParentFingerprint.originalClassDef
|
||||||
|
).method.apply {
|
||||||
|
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.MOVE_RESULT_OBJECT)
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
move-result-object v0
|
||||||
|
invoke-static { v0, p1, p2, p3 }, $EXTENSION_CLASS_DESCRIPTOR->isStringFeatureFlagEnabled(Ljava/lang/String;JLjava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v0
|
||||||
|
return-object v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// There exists other experimental accessor methods for byte[]
|
||||||
|
// and wrappers for obfuscated classes, but currently none of those are hooked.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package app.revanced.patches.shared.misc.debugging
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal val experimentalFeatureFlagParentFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||||
|
returns("L")
|
||||||
|
parameters("L", "J", "[B")
|
||||||
|
strings("Unable to parse proto typed experiment flag: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val experimentalBooleanFeatureFlagFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||||
|
returns("Z")
|
||||||
|
parameters("L", "J", "Z")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val experimentalDoubleFeatureFlagFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("D")
|
||||||
|
parameters("J", "D")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val experimentalLongFeatureFlagFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("J")
|
||||||
|
parameters("J", "J")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val experimentalStringFeatureFlagFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("Ljava/lang/String;")
|
||||||
|
parameters("J", "Ljava/lang/String;")
|
||||||
|
}
|
||||||
@@ -1,144 +1,35 @@
|
|||||||
package app.revanced.patches.youtube.misc.debugging
|
package app.revanced.patches.youtube.misc.debugging
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
|
||||||
import app.revanced.patches.all.misc.resources.addResources
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
import app.revanced.patches.shared.misc.debugging.enableDebuggingPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
|
||||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
@Suppress("unused")
|
||||||
"Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;"
|
val enableDebuggingPatch = enableDebuggingPatch(
|
||||||
|
block = {
|
||||||
// TODO: Refactor this into a shared patch that can be used by both YT and YT Music.
|
dependsOn(
|
||||||
// Almost all of the feature flag hooks are the same between both apps.
|
sharedExtensionPatch,
|
||||||
val enableDebuggingPatch = bytecodePatch(
|
settingsPatch,
|
||||||
name = "Enable debugging",
|
|
||||||
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
|
|
||||||
) {
|
|
||||||
dependsOn(
|
|
||||||
sharedExtensionPatch,
|
|
||||||
settingsPatch,
|
|
||||||
addResourcesPatch,
|
|
||||||
versionCheckPatch
|
|
||||||
)
|
|
||||||
|
|
||||||
compatibleWith(
|
|
||||||
"com.google.android.youtube"(
|
|
||||||
"19.34.42",
|
|
||||||
"19.43.41",
|
|
||||||
"19.47.53",
|
|
||||||
"20.07.39",
|
|
||||||
"20.12.46",
|
|
||||||
"20.13.41",
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
compatibleWith(
|
||||||
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
"com.google.android.youtube"(
|
||||||
|
"19.34.42",
|
||||||
|
"19.43.41",
|
||||||
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
|
"20.12.46",
|
||||||
|
"20.13.41",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
executeBlock = {
|
||||||
addResources("youtube", "misc.debugging.enableDebuggingPatch")
|
addResources("youtube", "misc.debugging.enableDebuggingPatch")
|
||||||
|
},
|
||||||
PreferenceScreen.MISC.addPreferences(
|
hookStringFeatureFlag = true,
|
||||||
PreferenceScreenPreference(
|
preferenceScreen = PreferenceScreen.MISC,
|
||||||
key = "revanced_debug_screen",
|
additionalDebugPreferences = listOf(SwitchPreference("revanced_debug_protobuffer"))
|
||||||
sorting = Sorting.UNSORTED,
|
)
|
||||||
preferences = setOf(
|
|
||||||
SwitchPreference("revanced_debug"),
|
|
||||||
SwitchPreference("revanced_debug_protobuffer"),
|
|
||||||
SwitchPreference("revanced_debug_stacktrace"),
|
|
||||||
SwitchPreference("revanced_debug_toast_on_error"),
|
|
||||||
NonInteractivePreference(
|
|
||||||
"revanced_debug_export_logs_to_clipboard",
|
|
||||||
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
|
||||||
selectable = true
|
|
||||||
),
|
|
||||||
NonInteractivePreference(
|
|
||||||
"revanced_debug_logs_clear_buffer",
|
|
||||||
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
|
||||||
selectable = true
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hook the methods that look up if a feature flag is active.
|
|
||||||
experimentalBooleanFeatureFlagFingerprint.match(
|
|
||||||
experimentalFeatureFlagParentFingerprint.originalClassDef
|
|
||||||
).method.apply {
|
|
||||||
findInstructionIndicesReversedOrThrow(Opcode.RETURN).forEach { index ->
|
|
||||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
index,
|
|
||||||
"""
|
|
||||||
invoke-static { v$register, p1 }, $EXTENSION_CLASS_DESCRIPTOR->isBooleanFeatureFlagEnabled(ZLjava/lang/Long;)Z
|
|
||||||
move-result v$register
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
experimentalDoubleFeatureFlagFingerprint.match(
|
|
||||||
experimentalFeatureFlagParentFingerprint.originalClassDef
|
|
||||||
).method.apply {
|
|
||||||
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex,
|
|
||||||
"""
|
|
||||||
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
|
|
||||||
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isDoubleFeatureFlagEnabled(DJD)D
|
|
||||||
move-result-wide v0
|
|
||||||
return-wide v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
experimentalLongFeatureFlagFingerprint.match(
|
|
||||||
experimentalFeatureFlagParentFingerprint.originalClassDef
|
|
||||||
).method.apply {
|
|
||||||
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex,
|
|
||||||
"""
|
|
||||||
move-result-wide v0
|
|
||||||
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isLongFeatureFlagEnabled(JJJ)J
|
|
||||||
move-result-wide v0
|
|
||||||
return-wide v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
experimentalStringFeatureFlagFingerprint.match(
|
|
||||||
experimentalFeatureFlagParentFingerprint.originalClassDef
|
|
||||||
).method.apply {
|
|
||||||
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.MOVE_RESULT_OBJECT)
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex,
|
|
||||||
"""
|
|
||||||
move-result-object v0
|
|
||||||
invoke-static { v0, p1, p2, p3 }, $EXTENSION_CLASS_DESCRIPTOR->isStringFeatureFlagEnabled(Ljava/lang/String;JLjava/lang/String;)Ljava/lang/String;
|
|
||||||
move-result-object v0
|
|
||||||
return-object v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// There exists other experimental accessor methods for byte[]
|
|
||||||
// and wrappers for obfuscated classes, but currently none of those are hooked.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -163,6 +163,15 @@ Playback may not work"</string>
|
|||||||
<string name="revanced_debug_title">Debug logging</string>
|
<string name="revanced_debug_title">Debug logging</string>
|
||||||
<string name="revanced_debug_summary_on">Debug logs are enabled</string>
|
<string name="revanced_debug_summary_on">Debug logs are enabled</string>
|
||||||
<string name="revanced_debug_summary_off">Debug logs are disabled</string>
|
<string name="revanced_debug_summary_off">Debug logs are disabled</string>
|
||||||
|
<string name="revanced_debug_stacktrace_title">Log stack traces</string>
|
||||||
|
<string name="revanced_debug_stacktrace_summary_on">Debug logs include stack trace</string>
|
||||||
|
<string name="revanced_debug_stacktrace_summary_off">Debug logs do not include stack trace</string>
|
||||||
|
<string name="revanced_debug_toast_on_error_title">Show toast on ReVanced error</string>
|
||||||
|
<string name="revanced_debug_toast_on_error_summary_on">Toast is shown if error occurs</string>
|
||||||
|
<string name="revanced_debug_toast_on_error_summary_off">Toast is not shown if error occurs</string>
|
||||||
|
<string name="revanced_debug_toast_on_error_user_dialog_message">"Turning off error toasts hides all ReVanced error notifications.
|
||||||
|
|
||||||
|
You will not be notified of any unexpected events."</string>
|
||||||
<string name="revanced_debug_export_logs_to_clipboard_title">Export debug logs</string>
|
<string name="revanced_debug_export_logs_to_clipboard_title">Export debug logs</string>
|
||||||
<string name="revanced_debug_export_logs_to_clipboard_summary">Copies ReVanced debug logs to the clipboard</string>
|
<string name="revanced_debug_export_logs_to_clipboard_summary">Copies ReVanced debug logs to the clipboard</string>
|
||||||
<string name="revanced_debug_logs_disabled">Debug logging is disabled</string>
|
<string name="revanced_debug_logs_disabled">Debug logging is disabled</string>
|
||||||
@@ -209,15 +218,6 @@ Playback may not work"</string>
|
|||||||
This can help identify components when creating custom filters.
|
This can help identify components when creating custom filters.
|
||||||
|
|
||||||
However, enabling this will also log some user data such as your IP address."</string>
|
However, enabling this will also log some user data such as your IP address."</string>
|
||||||
<string name="revanced_debug_stacktrace_title">Log stack traces</string>
|
|
||||||
<string name="revanced_debug_stacktrace_summary_on">Debug logs include stack trace</string>
|
|
||||||
<string name="revanced_debug_stacktrace_summary_off">Debug logs do not include stack trace</string>
|
|
||||||
<string name="revanced_debug_toast_on_error_title">Show toast on ReVanced error</string>
|
|
||||||
<string name="revanced_debug_toast_on_error_summary_on">Toast is shown if error occurs</string>
|
|
||||||
<string name="revanced_debug_toast_on_error_summary_off">Toast is not shown if error occurs</string>
|
|
||||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"Turning off error toasts hides all ReVanced error notifications.
|
|
||||||
|
|
||||||
You will not be notified of any unexpected events."</string>
|
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||||
<string name="revanced_hide_album_cards_title">Hide album cards</string>
|
<string name="revanced_hide_album_cards_title">Hide album cards</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user