feat: Use modern style settings dialogs (#5109)

Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
MarcaD
2025-06-13 09:29:13 +02:00
committed by GitHub
co-authored by LisoUseInAIKyrios
parent 9e30c34e74
commit a426e2af50
99 changed files with 2343 additions and 1324 deletions
@@ -1,7 +1,7 @@
package app.revanced.patches.idaustria.detection.signature
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val spoofSignaturePatch = bytecodePatch(
@@ -24,12 +24,6 @@ val spoofSignaturePatch = bytecodePatch(
"77ef1be61b2c01ebdabddcbf53cc4b6fd9a3c445606ee77b3758162c80ad8f8137b3c6864e92db904807dcb2be9d7717dd21" +
"bf42c121d620ddfb7914f7a95c713d9e1c1b7bdb4a03d618e40cf7e9e235c0b5687e03b7ab3,publicExponent=10001}"
spoofSignatureFingerprint.method.addInstructions(
0,
"""
const-string v0, "$expectedSignature"
return-object v0
""",
)
spoofSignatureFingerprint.method.returnEarly(expectedSignature)
}
}
@@ -1,7 +1,7 @@
package app.revanced.patches.nunl.firebase
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val spoofCertificatePatch = bytecodePatch(
@@ -12,13 +12,7 @@ val spoofCertificatePatch = bytecodePatch(
execute {
getFingerprintHashForPackageFingerprints.forEach { fingerprint ->
fingerprint.method.addInstructions(
0,
"""
const-string v0, "eae41fc018df2731a9b6ae1ac327da44a288667b"
return-object v0
""",
)
fingerprint.method.returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b")
}
}
}
@@ -1,8 +1,8 @@
package app.revanced.patches.photomath.detection.deviceid
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.photomath.detection.signature.signatureDetectionPatch
import app.revanced.util.returnEarly
import kotlin.random.Random
@Suppress("unused")
@@ -15,12 +15,6 @@ val getDeviceIdPatch = bytecodePatch(
compatibleWith("com.microblink.photomath")
execute {
getDeviceIdFingerprint.method.replaceInstructions(
0,
"""
const-string v0, "${Random.nextLong().toString(16)}"
return-object v0
""",
)
getDeviceIdFingerprint.method.returnEarly(Random.nextLong().toString(16))
}
}
@@ -3,6 +3,7 @@ package app.revanced.patches.piccomafr.misc
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.util.returnEarly
@Suppress("unused")
val spoofAndroidDeviceIdPatch = bytecodePatch(
@@ -39,12 +40,6 @@ val spoofAndroidDeviceIdPatch = bytecodePatch(
) { it!!.matches("[A-Fa-f0-9]{16}".toRegex()) }
execute {
getAndroidIdFingerprint.method.addInstructions(
0,
"""
const-string v0, "$androidDeviceId"
return-object v0
""",
)
getAndroidIdFingerprint.method.returnEarly(androidDeviceId!!)
}
}
@@ -1,9 +1,9 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com") { clientIdOption ->
@@ -14,13 +14,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com")
execute {
// region Patch client id.
getClientIdFingerprint.method.addInstructions(
0,
"""
const-string v0, "$clientId"
return-object v0
""",
)
getClientIdFingerprint.method.returnEarly(clientId!!)
// endregion
@@ -1,9 +1,8 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.disablePiracyDetectionPatch
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.returnEarly
val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/authorize_callback") { clientIdOption ->
dependsOn(disablePiracyDetectionPatch)
@@ -19,13 +18,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/a
execute {
// region Patch client id.
getClientIdFingerprint.method.addInstructions(
0,
"""
const-string v0, "$clientId"
return-object v0
""",
)
getClientIdFingerprint.method.returnEarly(clientId!!)
// endregion
@@ -35,13 +28,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/a
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
authUtilityUserAgentFingerprint.method.replaceInstructions(
0,
"""
const-string v0, "$userAgent"
return-object v0
""",
)
authUtilityUserAgentFingerprint.method.returnEarly(userAgent)
// endregion
}
@@ -2,12 +2,12 @@ package app.revanced.patches.reddit.customclients.redditisfun.api
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.Match
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@@ -54,13 +54,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
getUserAgentFingerprint.method.addInstructions(
0,
"""
const-string v0, "$userAgent"
return-object v0
""",
)
getUserAgentFingerprint.method.returnEarly(userAgent)
// endregion
@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.slide.api
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.returnEarly
val spoofClientPatch = spoofClientPatch(redirectUri = "http://www.ccrama.me") { clientIdOption ->
compatibleWith("me.ccrama.redditslide")
@@ -9,12 +9,6 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://www.ccrama.me") {
val clientId by clientIdOption
execute {
getClientIdFingerprint.method.addInstructions(
0,
"""
const-string v0, "$clientId"
return-object v0
""",
)
getClientIdFingerprint.method.returnEarly(clientId!!)
}
}
@@ -1,14 +1,14 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.api
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import java.util.*
import java.util.Base64
val spoofClientPatch = spoofClientPatch(
redirectUri = "http://redditsync/auth",
@@ -28,13 +28,8 @@ val spoofClientPatch = spoofClientPatch(
getBearerTokenFingerprint.match(getAuthorizationStringFingerprint.originalClassDef).method.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
addInstructions(
0,
"""
const-string v0, "Basic $auth"
return-object v0
""",
)
returnEarly("Basic $auth")
val occurrenceIndex =
getAuthorizationStringFingerprint.stringMatches!!.first().index
@@ -63,23 +58,19 @@ val spoofClientPatch = spoofClientPatch(
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
getUserAgentFingerprint.method.replaceInstruction(
0,
"""
const-string v0, "$userAgent"
return-object v0
""",
)
getUserAgentFingerprint.method.returnEarly(userAgent)
// endregion
// region Patch Imgur API URL.
val apiUrlIndex = imgurImageAPIFingerprint.stringMatches!!.first().index
imgurImageAPIFingerprint.method.replaceInstruction(
apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"",
)
imgurImageAPIFingerprint.let {
val apiUrlIndex = it.stringMatches!!.first().index
it.method.replaceInstruction(
apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"",
)
}
// endregion
}
@@ -84,7 +84,7 @@ fun checkEnvironmentPatch(
fun invokeCheck() = mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 },$EXTENSION_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
)
setPatchInfo()
@@ -3,11 +3,11 @@ package app.revanced.patches.shared.misc.extension
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.FingerprintBuilder
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.Method
import java.net.URLDecoder
import java.util.jar.JarFile
@@ -80,14 +80,7 @@ fun sharedExtensionPatch(
}
val manifestValue = getPatchesManifestEntry("Version")
addInstructions(
0,
"""
const-string v0, "$manifestValue"
return-object v0
""",
)
returnEarly(manifestValue)
}
}
}
@@ -0,0 +1,23 @@
package app.revanced.patches.shared.misc.settings
import app.revanced.patcher.fingerprint
import app.revanced.patches.shared.misc.extension.EXTENSION_CLASS_DESCRIPTOR
import com.android.tools.smali.dexlib2.AccessFlags
internal val themeLightColorResourceNameFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, classDef ->
method.name == "getThemeLightColorResourceName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}
internal val themeDarkColorResourceNameFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, classDef ->
method.name == "getThemeDarkColorResourceName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}
@@ -1,6 +1,7 @@
package app.revanced.patches.shared.misc.settings
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResource
import app.revanced.patches.all.misc.resources.addResources
@@ -13,6 +14,7 @@ import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.getNode
import app.revanced.util.insertFirst
import app.revanced.util.returnEarly
import org.w3c.dom.Node
// TODO: Delete this on next major version bump.
@@ -22,6 +24,30 @@ fun settingsPatch (
preferences: Set<BasePreference>,
) = settingsPatch(listOf(rootPreference), preferences)
private var themeForegroundColor : String? = null
private var themeBackgroundColor : String? = null
/**
* Sets the default theme colors used in various ReVanced specific settings menus.
* By default these colors are white and black, but instead can be set to the
* same color the target app uses for it's own settings.
*/
fun overrideThemeColors(foregroundColor: String, backgroundColor: String) {
themeForegroundColor = foregroundColor
themeBackgroundColor = backgroundColor
}
private val settingsColorPatch = bytecodePatch {
finalize {
if (themeForegroundColor != null) {
themeLightColorResourceNameFingerprint.method.returnEarly(themeForegroundColor!!)
}
if (themeBackgroundColor != null) {
themeDarkColorResourceNameFingerprint.method.returnEarly(themeBackgroundColor!!)
}
}
}
/**
* A resource patch that adds settings to a settings fragment.
*
@@ -33,12 +59,28 @@ fun settingsPatch (
rootPreferences: List<Pair<BasePreference, String>>? = null,
preferences: Set<BasePreference>,
) = resourcePatch {
dependsOn(addResourcesPatch)
dependsOn(addResourcesPatch, settingsColorPatch)
execute {
copyResources(
"settings",
ResourceGroup("xml", "revanced_prefs.xml", "revanced_prefs_icons.xml"),
ResourceGroup("drawable",
// CustomListPreference resources.
"revanced_ic_dialog_alert.xml",
"revanced_settings_arrow_time.xml",
"revanced_settings_circle_background.xml",
"revanced_settings_cursor.xml",
"revanced_settings_custom_checkmark.xml",
"revanced_settings_search_icon.xml",
"revanced_settings_toolbar_arrow_left.xml",
),
ResourceGroup("layout",
"revanced_custom_list_item_checked.xml",
// Color picker.
"revanced_color_dot_widget.xml",
"revanced_color_picker.xml",
)
)
addResources("shared", "misc.settings.settingsResourcePatch")
@@ -12,7 +12,7 @@ import org.w3c.dom.Document
* @param summaryKey The preference summary key.
* @param icon The preference icon resource name.
* @param layout Layout declaration.
* @param tag The preference tag.
* @param tag The preference class type.
* @param entriesKey The entries array key.
* @param entryValuesKey The entry values array key.
*/
@@ -20,10 +20,12 @@ import org.w3c.dom.Document
class ListPreference(
key: String? = null,
titleKey: String = "${key}_title",
summaryKey: String? = "${key}_summary",
/** Summary key is ignored and will be removed soon */
//@Deprecated
summaryKey: String? = null,
icon: String? = null,
layout: String? = null,
tag: String = "ListPreference",
tag: String = "app.revanced.extension.shared.settings.preference.CustomDialogListPreference",
val entriesKey: String? = "${key}_entries",
val entryValuesKey: String? = "${key}_entry_values"
) : BasePreference(key, titleKey, summaryKey, icon, layout, tag) {
@@ -25,7 +25,7 @@ val embeddedAdsPatch = bytecodePatch(
addResources("twitch", "ad.embedded.embeddedAdsPatch")
PreferenceScreen.ADS.SURESTREAM.addPreferences(
ListPreference("revanced_block_embedded_ads", summaryKey = null),
ListPreference("revanced_block_embedded_ads"),
)
// Inject OkHttp3 application interceptor
@@ -34,10 +34,7 @@ val showDeletedMessagesPatch = bytecodePatch(
addResources("twitch", "chat.antidelete.showDeletedMessagesPatch")
PreferenceScreen.CHAT.GENERAL.addPreferences(
ListPreference(
key = "revanced_show_deleted_messages",
summaryKey = null,
),
ListPreference("revanced_show_deleted_messages")
)
// Spoiler mode: Force set hasModAccess member to true in constructor
@@ -1,7 +1,7 @@
package app.revanced.patches.warnwetter.misc.firebasegetcert
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
val firebaseGetCertPatch = bytecodePatch(
description = "Spoofs the X-Android-Cert header.",
@@ -10,13 +10,7 @@ val firebaseGetCertPatch = bytecodePatch(
execute {
listOf(getRegistrationCertFingerprint, getMessagingCertFingerprint).forEach { match ->
match.method.addInstructions(
0,
"""
const-string v0, "0799DDF0414D3B3475E88743C91C0676793ED450"
return-object v0
""",
)
match.method.returnEarly("0799DDF0414D3B3475E88743C91C0676793ED450")
}
}
}
@@ -11,10 +11,14 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPref
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.TextPreference
import app.revanced.patches.youtube.misc.playercontrols.*
import app.revanced.patches.youtube.misc.playercontrols.addBottomControl
import app.revanced.patches.youtube.misc.playercontrols.initializeBottomControl
import app.revanced.patches.youtube.misc.playercontrols.injectVisibilityCheckCall
import app.revanced.patches.youtube.misc.playercontrols.playerControlsPatch
import app.revanced.patches.youtube.misc.playercontrols.playerControlsResourcePatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
@@ -83,12 +87,10 @@ val downloadsPatch = bytecodePatch(
injectVisibilityCheckCall(BUTTON_DESCRIPTOR)
// Main activity is used to launch downloader intent.
mainActivityFingerprint.method.apply {
addInstruction(
implementation!!.instructions.lastIndex,
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V",
)
}
mainActivityOnCreateFingerprint.method.addInstruction(
1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V"
)
offlineVideoEndpointFingerprint.method.apply {
addInstructionsWithLabels(
@@ -14,7 +14,7 @@ import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_43_or_greater
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityFingerprint
import app.revanced.patches.youtube.shared.mainActivityConstructorFingerprint
import app.revanced.util.*
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
@@ -43,10 +43,7 @@ private val swipeControlsResourcePatch = resourcePatch {
SwitchPreference("revanced_swipe_haptic_feedback"),
SwitchPreference("revanced_swipe_save_and_restore_brightness"),
SwitchPreference("revanced_swipe_lowest_value_enable_auto_brightness"),
ListPreference(
"revanced_swipe_overlay_style",
summaryKey = null,
),
ListPreference("revanced_swipe_overlay_style"),
TextPreference("revanced_swipe_overlay_background_opacity", inputType = InputType.NUMBER),
TextPreference("revanced_swipe_overlay_progress_brightness_color",
tag = "app.revanced.extension.shared.settings.preference.ColorPickerPreference",
@@ -103,7 +100,7 @@ val swipeControlsPatch = bytecodePatch(
execute {
val wrapperClass = swipeControlsHostActivityFingerprint.classDef
val targetClass = mainActivityFingerprint.classDef
val targetClass = mainActivityConstructorFingerprint.classDef
// Inject the wrapper class from the extension into the class hierarchy of MainActivity.
wrapperClass.setSuperClass(targetClass.superclass)
@@ -47,10 +47,7 @@ val changeFormFactorPatch = bytecodePatch(
addResources("youtube", "layout.formfactor.changeFormFactorPatch")
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
ListPreference(
"revanced_change_form_factor",
summaryKey = null,
)
ListPreference("revanced_change_form_factor")
)
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
@@ -184,23 +184,18 @@ val miniplayerPatch = bytecodePatch(
preferences +=
if (is_20_03_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
)
ListPreference("revanced_miniplayer_type")
} else if (is_19_43_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
key = "revanced_miniplayer_type",
entriesKey = "revanced_miniplayer_type_legacy_19_43_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_43_entry_values",
entryValuesKey = "revanced_miniplayer_type_legacy_19_43_entry_values"
)
} else {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
key = "revanced_miniplayer_type",
entriesKey = "revanced_miniplayer_type_legacy_19_16_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_16_entry_values",
entryValuesKey = "revanced_miniplayer_type_legacy_19_16_entry_values"
)
}
@@ -49,10 +49,7 @@ internal val exitFullscreenPatch = bytecodePatch(
addResources("youtube", "layout.player.fullscreen.exitFullscreenPatch")
PreferenceScreen.PLAYER.addPreferences(
ListPreference(
"revanced_exit_fullscreen",
summaryKey = null,
)
ListPreference("revanced_exit_fullscreen")
)
autoRepeatFingerprint.match(autoRepeatParentFingerprint.originalClassDef).method.apply {
@@ -70,8 +70,7 @@ val shortsAutoplayPatch = bytecodePatch(
// Main activity is used to check if app is in pip mode.
mainActivityOnCreateFingerprint.method.addInstruction(
1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V",
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V",
)
val reelEnumClass = reelEnumConstructorFingerprint.originalClassDef.type
@@ -79,14 +79,10 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
PreferenceScreen.SHORTS.addPreferences(
if (is_19_46_or_greater) {
ListPreference(
key = "revanced_shorts_player_type",
summaryKey = null,
)
ListPreference("revanced_shorts_player_type")
} else {
ListPreference(
key = "revanced_shorts_player_type",
summaryKey = null,
entriesKey = "revanced_shorts_player_type_legacy_entries",
entryValuesKey = "revanced_shorts_player_type_legacy_entry_values"
)
@@ -83,7 +83,7 @@ val spoofAppVersionPatch = bytecodePatch(
if (is_19_43_or_greater) {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
summaryKey = null
)
} else {
ListPreference(
@@ -53,7 +53,6 @@ val changeStartPagePatch = bytecodePatch(
preferences = setOf(
ListPreference(
key = "revanced_change_start_page",
summaryKey = null,
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference"
),
SwitchPreference("revanced_change_start_page_always")
@@ -24,26 +24,6 @@ internal val lithoThemeFingerprint = fingerprint {
}
}
internal val themeHelperDarkColorFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, _ ->
method.name == "darkThemeResourceName" &&
method.definingClass == "Lapp/revanced/extension/youtube/ThemeHelper;"
}
}
internal val themeHelperLightColorFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, _ ->
method.name == "lightThemeResourceName" &&
method.definingClass == "Lapp/revanced/extension/youtube/ThemeHelper;"
}
}
internal const val GRADIENT_LOADING_SCREEN_AB_CONSTANT = 45412406L
internal val useGradientLoadingScreenFingerprint = fingerprint {
@@ -1,6 +1,5 @@
package app.revanced.patches.youtube.layout.theme
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
@@ -8,6 +7,7 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.overrideThemeColors
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.InputType
import app.revanced.patches.shared.misc.settings.preference.ListPreference
@@ -22,16 +22,17 @@ import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.childElementsSequence
import app.revanced.util.forEachChildElement
import app.revanced.util.insertLiteralOverride
import org.w3c.dom.Element
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/theme/ThemePatch;"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/ThemePatch;"
val themePatch = bytecodePatch(
name = "Theme",
description = "Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).",
description = "Adds options for theming and applies a custom background theme " +
"(dark background theme defaults to amoled black).",
) {
val amoledBlackColor = "@android:color/black"
val whiteColor = "@android:color/white"
@@ -109,27 +110,23 @@ val themePatch = bytecodePatch(
)
)
overrideThemeColors(lightThemeBackgroundColor!!, darkThemeBackgroundColor!!)
// Edit theme colors via resources.
document("res/values/colors.xml").use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
val children = resourcesNode.childNodes
for (i in 0 until children.length) {
val node = children.item(i) as? Element ?: continue
resourcesNode.childElementsSequence().forEach { node ->
when (node.getAttribute("name")) {
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98",
"yt_black2", "yt_black3", "yt_black4", "yt_status_bar_background_dark",
"material_grey_850",
-> node.textContent = darkThemeBackgroundColor
node.textContent =
when (node.getAttribute("name")) {
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3",
"yt_black4", "yt_status_bar_background_dark", "material_grey_850",
-> darkThemeBackgroundColor ?: continue
"yt_white1", "yt_white1_opacity95", "yt_white1_opacity98",
"yt_white2", "yt_white3", "yt_white4",
-> lightThemeBackgroundColor ?: continue
else -> continue
}
"yt_white1", "yt_white1_opacity95", "yt_white1_opacity98",
"yt_white2", "yt_white3", "yt_white4",
-> node.textContent = lightThemeBackgroundColor
}
}
}
@@ -151,67 +148,56 @@ val themePatch = bytecodePatch(
}
}
val splashBackgroundColor = "revanced_splash_background_color"
// Add a dynamic background color to the colors.xml file.
lightThemeBackgroundColor?.let {
addColorResource("res/values/colors.xml", splashBackgroundColor, it)
}
darkThemeBackgroundColor?.let {
addColorResource("res/values-night/colors.xml", splashBackgroundColor, it)
}
val splashBackgroundColorKey = "revanced_splash_background_color"
addColorResource("res/values/colors.xml", splashBackgroundColorKey, lightThemeBackgroundColor!!)
addColorResource("res/values-night/colors.xml", splashBackgroundColorKey, darkThemeBackgroundColor!!)
// Edit splash screen files and change the background color,
// if the background colors are set.
if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) {
val splashScreenResourceFiles = listOf(
"res/drawable/quantum_launchscreen_youtube.xml",
"res/drawable-sw600dp/quantum_launchscreen_youtube.xml",
)
splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile ->
document(resourceFile).use { document ->
document.getElementsByTagName("layer-list").item(0).forEachChildElement { node ->
if (node.hasAttribute("android:drawable")) {
node.setAttribute("android:drawable", "@color/$splashBackgroundColor")
return@editSplashScreen
}
arrayOf(
"res/drawable/quantum_launchscreen_youtube.xml",
"res/drawable-sw600dp/quantum_launchscreen_youtube.xml",
).forEach editSplashScreen@{ resourceFileName ->
document(resourceFileName).use { document ->
document.getElementsByTagName("layer-list").item(0).forEachChildElement { node ->
if (node.hasAttribute("android:drawable")) {
node.setAttribute("android:drawable", "@color/$splashBackgroundColorKey")
return@editSplashScreen
}
throw PatchException("Failed to modify launch screen")
}
}
// Fix the splash screen dark mode background color.
// In 19.32+ the dark mode splash screen is white and fades to black.
// Maybe it's a bug in YT, or maybe it intentionally. Who knows.
document("res/values-night-v27/styles.xml").use { document ->
// Create a night mode specific override for the splash screen background.
val style = document.createElement("style")
style.setAttribute("name", "Theme.YouTube.Home")
style.setAttribute("parent", "@style/Base.V27.Theme.YouTube.Home")
// Fix status and navigation bar showing white on some Android devices,
// such as SDK 28 Android 10 medium tablet.
val colorSplashBackgroundColor = "@color/$splashBackgroundColor"
arrayOf(
"android:navigationBarColor" to colorSplashBackgroundColor,
"android:windowBackground" to colorSplashBackgroundColor,
"android:colorBackground" to colorSplashBackgroundColor,
"colorPrimaryDark" to colorSplashBackgroundColor,
"android:windowLightStatusBar" to "false",
).forEach { (name, value) ->
val styleItem = document.createElement("item")
styleItem.setAttribute("name", name)
styleItem.textContent = value
style.appendChild(styleItem)
}
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild(style)
throw PatchException("Failed to modify launch screen")
}
}
// Fix the splash screen dark mode background color.
// In 19.32+ the dark mode splash screen is white and fades to black.
// Maybe it's a bug in YT, or maybe it intentionally. Who knows.
document("res/values-night-v27/styles.xml").use { document ->
// Create a night mode specific override for the splash screen background.
val style = document.createElement("style")
style.setAttribute("name", "Theme.YouTube.Home")
style.setAttribute("parent", "@style/Base.V27.Theme.YouTube.Home")
// Fix status and navigation bar showing white on some Android devices,
// such as SDK 28 Android 10 medium tablet.
val colorSplashBackgroundColor = "@color/$splashBackgroundColorKey"
arrayOf(
"android:navigationBarColor" to colorSplashBackgroundColor,
"android:windowBackground" to colorSplashBackgroundColor,
"android:colorBackground" to colorSplashBackgroundColor,
"colorPrimaryDark" to colorSplashBackgroundColor,
"android:windowLightStatusBar" to "false",
).forEach { (name, value) ->
val styleItem = document.createElement("item")
styleItem.setAttribute("name", name)
styleItem.textContent = value
style.appendChild(styleItem)
}
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild(style)
}
}
}
)
@@ -237,10 +223,7 @@ val themePatch = bytecodePatch(
if (is_19_47_or_greater) {
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
ListPreference(
key = "splash_screen_animation_style",
summaryKey = null
)
ListPreference("splash_screen_animation_style")
)
}
@@ -257,21 +240,6 @@ val themePatch = bytecodePatch(
)
}
arrayOf(
themeHelperLightColorFingerprint to lightThemeBackgroundColor,
themeHelperDarkColorFingerprint to darkThemeBackgroundColor,
).forEach { (fingerprint, color) ->
fingerprint.method.apply {
addInstructions(
0,
"""
const-string v0, "$color"
return-object v0
""",
)
}
}
lithoColorOverrideHook(EXTENSION_CLASS_DESCRIPTOR, "getValue")
}
}
@@ -50,34 +50,29 @@ val alternativeThumbnailsPatch = bytecodePatch(
val values = "revanced_alt_thumbnail_options_entry_values"
PreferenceScreen.ALTERNATIVE_THUMBNAILS.addPreferences(
ListPreference(
"revanced_alt_thumbnail_home",
summaryKey = null,
key = "revanced_alt_thumbnail_home",
entriesKey = entries,
entryValuesKey = values,
entryValuesKey = values
),
ListPreference(
"revanced_alt_thumbnail_subscription",
summaryKey = null,
key = "revanced_alt_thumbnail_subscription",
entriesKey = entries,
entryValuesKey = values,
entryValuesKey = values
),
ListPreference(
"revanced_alt_thumbnail_library",
summaryKey = null,
key = "revanced_alt_thumbnail_library",
entriesKey = entries,
entryValuesKey = values,
entryValuesKey = values
),
ListPreference(
"revanced_alt_thumbnail_player",
summaryKey = null,
key = "revanced_alt_thumbnail_player",
entriesKey = entries,
entryValuesKey = values,
entryValuesKey = values
),
ListPreference(
"revanced_alt_thumbnail_search",
summaryKey = null,
key = "revanced_alt_thumbnail_search",
entriesKey = entries,
entryValuesKey = values,
entryValuesKey = values
),
NonInteractivePreference(
"revanced_alt_thumbnail_dearrow_about",
@@ -89,7 +84,7 @@ val alternativeThumbnailsPatch = bytecodePatch(
TextPreference("revanced_alt_thumbnail_dearrow_api_url"),
NonInteractivePreference("revanced_alt_thumbnail_stills_about"),
SwitchPreference("revanced_alt_thumbnail_stills_fast"),
ListPreference("revanced_alt_thumbnail_stills_time", summaryKey = null),
ListPreference("revanced_alt_thumbnail_stills_time"),
)
addImageUrlHook(EXTENSION_CLASS_DESCRIPTOR)
@@ -4,15 +4,6 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val onBackPressedFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
opcodes(Opcode.RETURN_VOID)
custom { method, classDef ->
method.name == "onBackPressed" && classDef.endsWith("MainActivity;")
}
}
internal val scrollPositionFingerprint = fingerprint {
accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL)
returns("V")
@@ -2,6 +2,7 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
@@ -10,7 +11,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/FixBackToExitGesturePatch;"
internal val fixBackToExitGesturePatch = bytecodePatch(
description = "Fixes the swipe back to exit gesture.",
description = "Fixes the swipe back to exit gesture."
) {
execute {
@@ -36,12 +37,12 @@ internal val fixBackToExitGesturePatch = bytecodePatch(
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->onScrollingViews()V"
)
}
}
onBackPressedFingerprint.let {
it.method.addInstruction(
it.patternMatch!!.endIndex,
mainActivityOnBackPressedFingerprint.method.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID)
addInstruction(
index,
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V"
)
}
@@ -42,15 +42,6 @@ internal val initializeButtonsFingerprint = fingerprint {
literal { imageOnlyTabResourceId }
}
internal val mainActivityOnBackPressedFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters()
custom { method, classDef ->
method.name == "onBackPressed" && classDef.endsWith("MainActivity;")
}
}
/**
* Extension method, used for callback into to other patches.
* Specifically, [navigationButtonsPatch].
@@ -15,6 +15,7 @@ import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater
import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
@@ -3,7 +3,6 @@ package app.revanced.patches.youtube.misc.settings
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val licenseActivityOnCreateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
@@ -18,13 +17,9 @@ internal val setThemeFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters()
opcodes(Opcode.RETURN_OBJECT)
literal { appearanceStringId }
}
/**
* Added in YouTube v19.04.38.
*/
internal const val CAIRO_CONFIG_LITERAL_VALUE = 45532100L
internal val cairoFragmentConfigFingerprint = fingerprint {
@@ -1,9 +1,7 @@
package app.revanced.patches.youtube.misc.settings
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
@@ -13,15 +11,32 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.*
import app.revanced.patches.shared.misc.settings.overrideThemeColors
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.InputType
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
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.TextPreference
import app.revanced.patches.shared.misc.settings.settingsPatch
import app.revanced.patches.youtube.misc.check.checkEnvironmentPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.fix.playbackspeed.fixPlaybackSpeedWhilePlayingPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.*
import app.revanced.util.ResourceGroup
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.copyResources
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertLiteralOverride
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
@@ -30,7 +45,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.util.MethodUtil
// Used by a fingerprint() from SettingsPatch.
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
internal var appearanceStringId = -1L
private set
@@ -69,13 +86,13 @@ private val settingsResourcePatch = resourcePatch {
)
execute {
// Used for a fingerprint from SettingsPatch.
appearanceStringId = resourceMappings["string", "app_theme_appearance_dark"]
// Use same colors as stock YouTube.
overrideThemeColors("@color/yt_white1", "@color/yt_black3")
arrayOf(
ResourceGroup("drawable",
"revanced_settings_circle_background.xml",
"revanced_settings_cursor.xml",
"revanced_settings_icon.xml",
"revanced_settings_screen_00_about.xml",
"revanced_settings_screen_01_ads.xml",
@@ -92,11 +109,10 @@ private val settingsResourcePatch = resourcePatch {
"revanced_settings_screen_12_video.xml",
),
ResourceGroup("layout",
"revanced_color_dot_widget.xml",
"revanced_color_picker.xml",
"revanced_preference_with_icon_no_search_result.xml",
"revanced_search_suggestion_item.xml",
"revanced_settings_with_toolbar.xml"),
"revanced_settings_with_toolbar.xml"
),
ResourceGroup("menu", "revanced_search_menu.xml")
).forEach { resourceGroup ->
copyResources("settings", resourceGroup)
@@ -170,12 +186,6 @@ val settingsPatch = bytecodePatch(
checkEnvironmentPatch,
)
val extensionPackage = "app/revanced/extension/youtube"
val activityHookClassDescriptor = "L$extensionPackage/settings/LicenseActivityHook;"
val themeHelperDescriptor = "L$extensionPackage/ThemeHelper;"
val setThemeMethodName = "setTheme"
execute {
addResources("youtube", "misc.settings.settingsPatch")
@@ -185,7 +195,7 @@ val settingsPatch = bytecodePatch(
icon = "@drawable/revanced_settings_screen_00_about",
layout = "@layout/preference_with_icon",
summaryKey = null,
tag = "app.revanced.extension.youtube.settings.preference.ReVancedYouTubeAboutPreference",
tag = "app.revanced.extension.shared.settings.preference.ReVancedAboutPreference",
selectable = true,
)
@@ -210,31 +220,10 @@ val settingsPatch = bytecodePatch(
),
ListPreference(
key = "revanced_language",
summaryKey = null,
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference"
)
)
setThemeFingerprint.method.let { setThemeMethod ->
setThemeMethod.implementation!!.instructions.mapIndexedNotNull { i, instruction ->
if (instruction.opcode == Opcode.RETURN_OBJECT) i else null
}.asReversed().forEach { returnIndex ->
// The following strategy is to replace the return instruction with the setTheme instruction,
// then add a return instruction after the setTheme instruction.
// This is done because the return instruction is a target of another instruction.
setThemeMethod.apply {
// This register is returned by the setTheme method.
val register = getInstruction<OneRegisterInstruction>(returnIndex).registerA
replaceInstruction(
returnIndex,
"invoke-static { v$register }, " +
"$themeHelperDescriptor->$setThemeMethodName(Ljava/lang/Enum;)V",
)
addInstruction(returnIndex + 1, "return-object v$register")
}
}
}
// Modify the license activity and remove all existing layout code.
// Must modify an existing activity and cannot add a new activity to the manifest,
@@ -243,9 +232,9 @@ val settingsPatch = bytecodePatch(
licenseActivityOnCreateFingerprint.method.addInstructions(
1,
"""
invoke-static { p0 }, $activityHookClassDescriptor->initialize(Landroid/app/Activity;)V
invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V
return-void
""",
"""
)
// Remove other methods as they will break as the onCreate method is modified above.
@@ -267,7 +256,7 @@ val settingsPatch = bytecodePatch(
).toMutable().apply {
addInstructions(
"""
invoke-static { p1 }, $activityHookClassDescriptor->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
move-result-object p1
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
return-void
@@ -278,10 +267,23 @@ val settingsPatch = bytecodePatch(
methods.add(attachBaseContext)
}
// Update shared dark mode status based on YT theme.
// This is needed because YT allows forcing light/dark mode
// which then differs from the system dark mode status.
setThemeFingerprint.method.apply {
findInstructionIndicesReversedOrThrow(Opcode.RETURN_OBJECT).forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructionsAtControlFlowLabel(
index,
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
)
}
}
// Add setting to force cairo settings fragment on/off.
cairoFragmentConfigFingerprint.method.insertLiteralOverride(
CAIRO_CONFIG_LITERAL_VALUE,
"$activityHookClassDescriptor->useCairoSettingsFragment(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
)
}
@@ -48,10 +48,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_video_streams"),
ListPreference(
"revanced_spoof_video_streams_client_type",
summaryKey = null,
),
ListPreference("revanced_spoof_video_streams_client_type"),
NonInteractivePreference(
// Requires a key and title but the actual text is chosen at runtime.
key = "revanced_spoof_video_streams_about_android",
@@ -59,7 +56,6 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
),
ListPreference(
key = "revanced_spoof_video_streams_language",
summaryKey = null,
// Language strings are declared in Setting patch.
entriesKey = "revanced_language_entries",
entryValuesKey = "revanced_language_entry_values",
@@ -44,11 +44,20 @@ internal val layoutConstructorFingerprint = fingerprint {
strings("1.0x")
}
internal val mainActivityFingerprint = fingerprint {
internal val mainActivityConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters()
custom { _, classDef ->
classDef.endsWith("MainActivity;")
classDef.endsWith("/MainActivity;")
}
}
internal val mainActivityOnBackPressedFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters()
custom { method, classDef ->
method.name == "onBackPressed" && classDef.endsWith("/MainActivity;")
}
}
@@ -56,7 +65,7 @@ internal val mainActivityOnCreateFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("MainActivity;")
method.name == "onCreate" && classDef.endsWith("/MainActivity;")
}
}
@@ -37,29 +37,25 @@ val rememberVideoQualityPatch = bytecodePatch {
settingsMenuVideoQualityGroup.addAll(listOf(
ListPreference(
key = "revanced_video_quality_default_mobile",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
ListPreference(
key = "revanced_video_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference(
key = "revanced_shorts_quality_default_mobile",
summaryKey = null,
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values",
),
ListPreference(
key = "revanced_shorts_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values",
entryValuesKey = "revanced_shorts_quality_default_entry_values"
),
SwitchPreference("revanced_remember_shorts_quality_last_selected")
))
@@ -34,7 +34,6 @@ internal val rememberPlaybackSpeedPatch = bytecodePatch {
listOf(
ListPreference(
key = "revanced_playback_speed_default",
summaryKey = null,
// Entries and values are set by the extension code based on the actual speeds available.
entriesKey = null,
entryValuesKey = null,
@@ -742,16 +742,22 @@ private const val RETURN_TYPE_MISMATCH = "Mismatch between override type and Met
*
* For methods that return an object or any array type, calling this method with `false`
* will force the method to return a `null` value.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Boolean = false) {
val returnType = returnType.first()
check(returnType == 'Z' || (!value && (returnType in setOf('V', 'L', '[')))) { RETURN_TYPE_MISMATCH }
check(returnType == 'Z' || (!value && (returnType == 'V' || returnType == 'L' || returnType != '['))) {
RETURN_TYPE_MISMATCH
}
overrideReturnValue(value.toHexString(), false)
}
/**
* Overrides the first instruction of a method with a constant `Byte` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Byte) {
check(returnType.first() == 'B') { RETURN_TYPE_MISMATCH }
@@ -761,6 +767,8 @@ fun MutableMethod.returnEarly(value: Byte) {
/**
* Overrides the first instruction of a method with a constant `Short` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Short) {
check(returnType.first() == 'S') { RETURN_TYPE_MISMATCH }
@@ -770,6 +778,8 @@ fun MutableMethod.returnEarly(value: Short) {
/**
* Overrides the first instruction of a method with a constant `Char` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Char) {
check(returnType.first() == 'C') { RETURN_TYPE_MISMATCH }
@@ -779,6 +789,8 @@ fun MutableMethod.returnEarly(value: Char) {
/**
* Overrides the first instruction of a method with a constant `Int` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Int) {
check(returnType.first() == 'I') { RETURN_TYPE_MISMATCH }
@@ -788,6 +800,8 @@ fun MutableMethod.returnEarly(value: Int) {
/**
* Overrides the first instruction of a method with a constant `Long` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Long) {
check(returnType.first() == 'J') { RETURN_TYPE_MISMATCH }
@@ -797,6 +811,8 @@ fun MutableMethod.returnEarly(value: Long) {
/**
* Overrides the first instruction of a method with a constant `Float` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Float) {
check(returnType.first() == 'F') { RETURN_TYPE_MISMATCH }
@@ -806,12 +822,30 @@ fun MutableMethod.returnEarly(value: Float) {
/**
* Overrides the first instruction of a method with a constant `Double` return value.
* None of the method code will ever execute.
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: Double) {
check(returnType.first() == 'J') { RETURN_TYPE_MISMATCH }
overrideReturnValue(value.toString(), false)
}
/**
* Overrides the first instruction of a method with a constant String return value.
* None of the method code will ever execute.
*
* Target method must have return type
* Ljava/lang/String; or Ljava/lang/CharSequence;
*
* @see returnLate
*/
fun MutableMethod.returnEarly(value: String) {
check(returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;") {
RETURN_TYPE_MISMATCH
}
overrideReturnValue(value, false)
}
/**
* Overrides all return statements with a constant `Boolean` value.
* All method code is executed the same as unpatched.
@@ -826,7 +860,9 @@ fun MutableMethod.returnLate(value: Boolean) {
if (returnType == 'V') {
error("Cannot return late for Method of void type")
}
check(returnType == 'Z' || (!value && returnType in setOf('L', '['))) { RETURN_TYPE_MISMATCH }
check(returnType == 'Z' || (!value && (returnType == 'L' || returnType == '['))) {
RETURN_TYPE_MISMATCH
}
overrideReturnValue(value.toHexString(), true)
}
@@ -908,8 +944,29 @@ fun MutableMethod.returnLate(value: Double) {
overrideReturnValue(value.toString(), true)
}
/**
* Overrides all return statements with a constant String value.
* All method code is executed the same as unpatched.
*
* Target method must have return type
* Ljava/lang/String; or Ljava/lang/CharSequence;
*
* @see returnEarly
*/
fun MutableMethod.returnLate(value: String) {
check(returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;") {
RETURN_TYPE_MISMATCH
}
overrideReturnValue(value, true)
}
private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean) {
val instructions = when (returnType.first()) {
val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;" ) {
"""
const-string v0, "$value"
return-object v0
"""
} else when (returnType.first()) {
// If return type is an object, always return null.
'L', '[' -> {
"""