From 6bc243d1ab8caabd3f2741b611cb8dd50519b55a Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:32:08 +0900 Subject: [PATCH] feat(YouTube/Toolbar components): add `Enable wide search bar with header` settings --- .../general/toolbar/ToolBarComponentsPatch.kt | 103 +++++++++++++++--- .../ActionBarRingoBackgroundFingerprint.kt | 15 +++ .../ActionBarRingoTextFingerprint.kt | 16 +++ .../utils/resourceid/SharedResourceIdPatch.kt | 2 + .../youtube/settings/host/values/strings.xml | 3 + .../youtube/settings/xml/revanced_prefs.xml | 1 + 6 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoBackgroundFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoTextFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt index 2df4d5a59..86899ff6d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt @@ -7,10 +7,13 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.voicesearch.VoiceSearchUtils.patchXml +import app.revanced.patches.youtube.general.toolbar.fingerprints.ActionBarRingoBackgroundFingerprint +import app.revanced.patches.youtube.general.toolbar.fingerprints.ActionBarRingoTextFingerprint import app.revanced.patches.youtube.general.toolbar.fingerprints.AttributeResolverFingerprint import app.revanced.patches.youtube.general.toolbar.fingerprints.CreateSearchSuggestionsFingerprint import app.revanced.patches.youtube.general.toolbar.fingerprints.DrawerContentViewConstructorFingerprint @@ -26,12 +29,14 @@ import app.revanced.patches.youtube.utils.castbutton.CastButtonPatch import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch +import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ActionBarRingoBackground import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.VoiceSearch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.YtPremiumWordMarkHeader import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.YtWordMarkHeader import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts import app.revanced.patches.youtube.utils.toolbar.ToolBarHookPatch +import app.revanced.util.doRecursively import app.revanced.util.findMutableMethodOf import app.revanced.util.getTargetIndex import app.revanced.util.getTargetIndexWithMethodReferenceName @@ -48,7 +53,9 @@ 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.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i +import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.util.MethodUtil +import org.w3c.dom.Element @Suppress("DEPRECATION", "unused") object ToolBarComponentsPatch : BaseBytecodePatch( @@ -62,6 +69,7 @@ object ToolBarComponentsPatch : BaseBytecodePatch( ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( + ActionBarRingoBackgroundFingerprint, AttributeResolverFingerprint, CreateSearchSuggestionsFingerprint, DrawerContentViewConstructorFingerprint, @@ -72,7 +80,6 @@ object ToolBarComponentsPatch : BaseBytecodePatch( TrendingSearchConfigFingerprint ) ) { - private const val FLAG = "android:paddingStart" private const val TARGET_RESOURCE_PATH = "res/layout/action_bar_ringo_background.xml" private val ForceHideVoiceSearchButton by booleanPatchOption( @@ -84,7 +91,7 @@ object ToolBarComponentsPatch : BaseBytecodePatch( override fun execute(context: BytecodeContext) { - // region patch for change header + // region patch for change YouTube header // Invoke YouTube's header attribute into integrations. replaceHeaderAttributeId(context) @@ -144,19 +151,72 @@ object ToolBarComponentsPatch : BaseBytecodePatch( // region patch for enable wide search bar - YouActionBarFingerprint.resolve(context, setActionBarRingoMutableClass) + // Limitation: Premium header will not be applied for YouTube Premium users if the user uses the 'Wide search bar with header' option. + // This is because it forces the deprecated search bar to be loaded. + // As a solution to this limitation, 'Change YouTube header' patch is required. + ActionBarRingoBackgroundFingerprint.resultOrThrow().let { + ActionBarRingoTextFingerprint.resolve(context, it.classDef) + it.mutableMethod.apply { + val viewIndex = getWideLiteralInstructionIndex(ActionBarRingoBackground) + 2 + val viewRegister = getInstruction(viewIndex).registerA - SetWordMarkHeaderFingerprint.resultOrThrow().let { - val walkerMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex + 1) + addInstructions( + viewIndex + 1, + "invoke-static {v$viewRegister}, $GENERAL_CLASS_DESCRIPTOR->setWideSearchBarLayout(Landroid/view/View;)V" + ) + + val targetIndex = it.scanResult.patternScanResult!!.endIndex + 1 + val targetRegister = getInstruction(targetIndex).registerA - walkerMethod.apply { injectSearchBarHook( - implementation!!.instructions.size - 1, - "enableWideSearchBar" + targetIndex + 1, + targetRegister, + "enableWideSearchBarWithHeaderInverse" + ) + } + + it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } + .apply { + val staticCalls = implementation!!.instructions.withIndex() + .filter { instruction -> + val methodReference = ((instruction.value as? ReferenceInstruction)?.reference as? MethodReference) + methodReference?.parameterTypes?.size == 1 && + methodReference.returnType == "Z" + } + + if (staticCalls.size != 2) + throw PatchException("Size of staticCalls does not match: ${staticCalls.size}") + + mapOf( + staticCalls.elementAt(0).index to "enableWideSearchBar", + staticCalls.elementAt(1).index to "enableWideSearchBarWithHeader" + ).forEach { (index, descriptor) -> + val walkerMethod = getWalkerMethod(context, index) + + walkerMethod.apply { + injectSearchBarHook( + implementation!!.instructions.size - 1, + descriptor + ) + } + } + } + } + + ActionBarRingoTextFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val targetIndex = it.scanResult.patternScanResult!!.endIndex + 1 + val targetRegister = getInstruction(targetIndex).registerA + + injectSearchBarHook( + targetIndex + 1, + targetRegister, + "enableWideSearchBarWithHeader" ) } } + YouActionBarFingerprint.resolve(context, setActionBarRingoMutableClass) YouActionBarFingerprint.resultOrThrow().let { it.mutableMethod.apply { injectSearchBarHook( @@ -166,15 +226,16 @@ object ToolBarComponentsPatch : BaseBytecodePatch( } } + // This attribution cannot be changed in integrations, so change it in the xml file. contexts.xmlEditor[TARGET_RESOURCE_PATH].use { editor -> - val document = editor.file + editor.file.doRecursively { node -> + arrayOf("layout_marginStart").forEach replacement@{ replacement -> + if (node !is Element) return@replacement - with(document.getElementsByTagName("RelativeLayout").item(0)) { - if (attributes.getNamedItem(FLAG) != null) return@with - - document.createAttribute(FLAG) - .apply { value = "8.0dip" } - .let(attributes::setNamedItem) + node.getAttributeNode("android:$replacement")?.let { attribute -> + attribute.textContent = "0.0dip" + } + } } } @@ -346,8 +407,18 @@ object ToolBarComponentsPatch : BaseBytecodePatch( insertIndex: Int, descriptor: String ) { - val insertRegister = getInstruction(insertIndex).registerA + injectSearchBarHook( + insertIndex, + getInstruction(insertIndex).registerA, + descriptor + ) + } + private fun MutableMethod.injectSearchBarHook( + insertIndex: Int, + insertRegister: Int, + descriptor: String + ) { addInstructions( insertIndex, """ invoke-static {v$insertRegister}, $GENERAL_CLASS_DESCRIPTOR->$descriptor(Z)Z diff --git a/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoBackgroundFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoBackgroundFingerprint.kt new file mode 100644 index 000000000..e3e4867cc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoBackgroundFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.general.toolbar.fingerprints + +import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ActionBarRingoBackground +import app.revanced.util.fingerprint.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object ActionBarRingoBackgroundFingerprint : LiteralValueFingerprint( + returnType = "Landroid/view/View;", + parameters = listOf("Landroid/view/LayoutInflater;"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC + ), + literalSupplier = { ActionBarRingoBackground } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoTextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoTextFingerprint.kt new file mode 100644 index 000000000..4fc5d8a54 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/fingerprints/ActionBarRingoTextFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.general.toolbar.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.util.fingerprint.MethodReferenceNameFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object ActionBarRingoTextFingerprint : MethodReferenceNameFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC + ), + reference = { "setStartDelay" } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt index fcd768892..0128a9ae9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt @@ -19,6 +19,7 @@ import app.revanced.patches.shared.mapping.ResourceType.STYLE object SharedResourceIdPatch : ResourcePatch() { var AccountSwitcherAccessibility = -1L var ActionBarRingo = -1L + var ActionBarRingoBackground = -1L var ActionBarSearchResultsViewMic = -1L var AdAttribution = -1L var Appearance = -1L @@ -96,6 +97,7 @@ object SharedResourceIdPatch : ResourcePatch() { AccountSwitcherAccessibility = getId(STRING, "account_switcher_accessibility_label") ActionBarRingo = getId(LAYOUT, "action_bar_ringo") + ActionBarRingoBackground = getId(LAYOUT, "action_bar_ringo_background") ActionBarSearchResultsViewMic = getId(LAYOUT, "action_bar_search_results_view_mic") AdAttribution = getId(ID, "ad_attribution") Appearance = getId(STRING, "app_theme_appearance_dark") diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index 1095d1ffe..dc922cfaa 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -376,6 +376,9 @@ Some components may not be hidden." Enable wide search bar Wide search bar is enabled. Wide search bar is disabled. + Enable wide search bar with header + Wide search bar includes YouTube header. + Wide search bar does not include YouTube header. Enable wide search bar in You tab "Enabling this setting will disable the settings button in the You tab. diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml index d1ed2cadb..90a76afdb 100644 --- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -130,6 +130,7 @@ +