2022-07-31 12:15:26 +02:00
|
|
|
package app.revanced.patches.youtube.misc.settings.bytecode.patch
|
|
|
|
|
2022-12-18 22:18:28 +01:00
|
|
|
import app.revanced.extensions.toErrorResult
|
2022-07-31 12:15:26 +02:00
|
|
|
import app.revanced.patcher.annotation.Description
|
|
|
|
import app.revanced.patcher.annotation.Name
|
|
|
|
import app.revanced.patcher.annotation.Version
|
2022-10-05 04:03:10 +02:00
|
|
|
import app.revanced.patcher.data.BytecodeContext
|
2022-07-31 12:15:26 +02:00
|
|
|
import app.revanced.patcher.extensions.addInstruction
|
|
|
|
import app.revanced.patcher.extensions.addInstructions
|
2023-05-18 02:57:50 +02:00
|
|
|
import app.revanced.patcher.extensions.instruction
|
|
|
|
import app.revanced.patcher.extensions.replaceInstruction
|
2022-10-05 04:03:10 +02:00
|
|
|
import app.revanced.patcher.patch.BytecodePatch
|
2022-07-31 12:15:26 +02:00
|
|
|
import app.revanced.patcher.patch.PatchResult
|
|
|
|
import app.revanced.patcher.patch.PatchResultSuccess
|
2022-08-03 03:53:35 +02:00
|
|
|
import app.revanced.patcher.patch.annotations.DependsOn
|
2022-11-28 20:13:34 +01:00
|
|
|
import app.revanced.patches.shared.settings.preference.impl.Preference
|
|
|
|
import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen
|
2022-07-31 12:15:26 +02:00
|
|
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|
|
|
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint
|
2023-05-18 02:57:50 +02:00
|
|
|
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.SetThemeFingerprint
|
2022-07-31 12:15:26 +02:00
|
|
|
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch
|
2023-05-18 02:57:50 +02:00
|
|
|
import org.jf.dexlib2.Opcode
|
|
|
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
2022-08-22 01:59:43 +02:00
|
|
|
import org.jf.dexlib2.util.MethodUtil
|
2022-07-31 12:15:26 +02:00
|
|
|
|
2023-05-18 02:57:50 +02:00
|
|
|
@DependsOn([IntegrationsPatch::class, SettingsResourcePatch::class, ])
|
2022-07-31 12:15:26 +02:00
|
|
|
@Name("settings")
|
|
|
|
@Description("Adds settings for ReVanced to YouTube.")
|
|
|
|
@Version("0.0.1")
|
|
|
|
class SettingsPatch : BytecodePatch(
|
2023-05-18 02:57:50 +02:00
|
|
|
listOf(LicenseActivityFingerprint, SetThemeFingerprint)
|
2022-10-05 04:03:10 +02:00
|
|
|
) {
|
|
|
|
override fun execute(context: BytecodeContext): PatchResult {
|
2023-05-18 02:57:50 +02:00
|
|
|
// TODO: Remove this when it is only required at one place.
|
|
|
|
fun getSetThemeInstructionString(
|
2022-10-25 08:36:59 +02:00
|
|
|
registers: String = "v0",
|
|
|
|
classDescriptor: String = THEME_HELPER_DESCRIPTOR,
|
|
|
|
methodName: String = SET_THEME_METHOD_NAME,
|
|
|
|
parameters: String = "Ljava/lang/Object;"
|
2023-05-18 02:57:50 +02:00
|
|
|
) = "invoke-static { $registers }, $classDescriptor->$methodName($parameters)V"
|
2022-10-25 08:36:59 +02:00
|
|
|
|
2023-05-18 02:57:50 +02:00
|
|
|
SetThemeFingerprint.result?.mutableMethod?.let { setThemeMethod ->
|
|
|
|
setThemeMethod.implementation!!.instructions.mapIndexedNotNull { i, instruction ->
|
|
|
|
if (instruction.opcode == Opcode.RETURN_OBJECT) i else null
|
|
|
|
}
|
|
|
|
.asReversed() // Prevent index shifting.
|
|
|
|
.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.
|
2022-10-25 08:36:59 +02:00
|
|
|
|
2023-05-18 02:57:50 +02:00
|
|
|
setThemeMethod.apply {
|
|
|
|
// This register is returned by the setTheme method.
|
|
|
|
val register = instruction<OneRegisterInstruction>(returnIndex).registerA
|
2022-12-18 22:18:28 +01:00
|
|
|
|
2023-05-18 02:57:50 +02:00
|
|
|
val setThemeInstruction = getSetThemeInstructionString("v$register")
|
|
|
|
replaceInstruction(returnIndex, setThemeInstruction)
|
|
|
|
addInstruction(returnIndex + 1, "return-object v0")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} ?: return SetThemeFingerprint.toErrorResult()
|
2022-08-03 03:09:52 +02:00
|
|
|
|
2022-10-25 08:36:59 +02:00
|
|
|
// set the theme based on the preference of the device
|
2023-01-28 03:55:20 +01:00
|
|
|
LicenseActivityFingerprint.result!!.apply licenseActivity@{
|
|
|
|
mutableMethod.apply {
|
2022-10-25 08:36:59 +02:00
|
|
|
fun buildSettingsActivityInvokeString(
|
|
|
|
registers: String = "p0",
|
|
|
|
classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR,
|
|
|
|
methodName: String = "initializeSettings",
|
|
|
|
parameters: String = this@licenseActivity.mutableClass.type
|
2023-05-18 02:57:50 +02:00
|
|
|
) = getSetThemeInstructionString(registers, classDescriptor, methodName, parameters)
|
2022-10-25 08:36:59 +02:00
|
|
|
|
|
|
|
// initialize the settings
|
|
|
|
addInstructions(
|
2022-12-18 22:18:28 +01:00
|
|
|
1, """
|
2022-10-25 08:36:59 +02:00
|
|
|
${buildSettingsActivityInvokeString()}
|
|
|
|
return-void
|
|
|
|
"""
|
|
|
|
)
|
2022-07-31 12:15:26 +02:00
|
|
|
|
2022-10-25 08:36:59 +02:00
|
|
|
// set the current theme
|
|
|
|
addInstruction(0, buildSettingsActivityInvokeString(methodName = "setTheme"))
|
|
|
|
}
|
2022-08-03 03:09:52 +02:00
|
|
|
|
2022-10-25 08:36:59 +02:00
|
|
|
// remove method overrides
|
2023-01-28 03:55:20 +01:00
|
|
|
mutableClass.apply {
|
2022-10-25 08:36:59 +02:00
|
|
|
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
|
|
|
|
}
|
|
|
|
}
|
2022-08-22 01:59:43 +02:00
|
|
|
|
2022-07-31 12:15:26 +02:00
|
|
|
return PatchResultSuccess()
|
|
|
|
}
|
2022-08-03 03:09:52 +02:00
|
|
|
|
|
|
|
internal companion object {
|
2022-10-25 08:36:59 +02:00
|
|
|
private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations"
|
|
|
|
|
|
|
|
private const val SETTINGS_ACTIVITY_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settingsmenu/ReVancedSettingActivity;"
|
|
|
|
|
|
|
|
private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/utils/ThemeHelper;"
|
|
|
|
private const val SET_THEME_METHOD_NAME = "setTheme"
|
2022-08-22 01:59:43 +02:00
|
|
|
|
|
|
|
fun addString(identifier: String, value: String, formatted: Boolean = true) =
|
|
|
|
SettingsResourcePatch.addString(identifier, value, formatted)
|
|
|
|
|
2022-11-28 20:13:34 +01:00
|
|
|
fun addPreferenceScreen(preferenceScreen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) =
|
2022-08-22 01:59:43 +02:00
|
|
|
SettingsResourcePatch.addPreferenceScreen(preferenceScreen)
|
|
|
|
|
2022-12-18 22:18:28 +01:00
|
|
|
fun addPreference(preference: Preference) = SettingsResourcePatch.addPreference(preference)
|
2022-08-22 01:59:43 +02:00
|
|
|
|
|
|
|
fun renameIntentsTargetPackage(newPackage: String) {
|
|
|
|
SettingsResourcePatch.overrideIntentsTargetPackage = newPackage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Preference screens patches should add their settings to.
|
|
|
|
*/
|
2022-11-28 20:13:34 +01:00
|
|
|
internal object PreferenceScreen : AbstractPreferenceScreen() {
|
|
|
|
val ADS = Screen("ads", "Ads", "Ad related settings")
|
|
|
|
val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions")
|
|
|
|
val LAYOUT = Screen("layout", "Layout", "Settings related to the layout")
|
2023-05-13 01:32:41 +02:00
|
|
|
val VIDEO = Screen("video", "Video", "Settings related to the video player")
|
2022-11-28 20:13:34 +01:00
|
|
|
val MISC = Screen("misc", "Misc", "Miscellaneous patches")
|
|
|
|
|
|
|
|
override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) {
|
|
|
|
addPreferenceScreen(screen)
|
2022-08-22 01:59:43 +02:00
|
|
|
}
|
2022-08-03 03:09:52 +02:00
|
|
|
}
|
2022-08-22 01:59:43 +02:00
|
|
|
|
2022-11-28 20:13:34 +01:00
|
|
|
override fun close() = PreferenceScreen.close()
|
2022-10-25 08:36:59 +02:00
|
|
|
}
|