feat(YouTube): Add Change form factor
patch (#4217)
This commit is contained in:

committed by
GitHub

parent
da4aeac42b
commit
644ac5baa6
@ -0,0 +1,75 @@
|
||||
package app.revanced.patches.youtube.layout.formfactor
|
||||
|
||||
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.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeFormFactorPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val changeFormFactorPatch = bytecodePatch(
|
||||
name = "Change form factor",
|
||||
description = "Adds an option to change the UI appearance to a phone, tablet, or automotive device.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"18.38.44",
|
||||
"18.49.37",
|
||||
"19.16.39",
|
||||
"19.25.37",
|
||||
"19.34.42",
|
||||
"19.43.41",
|
||||
"19.45.38",
|
||||
"19.46.42",
|
||||
"19.47.53",
|
||||
),
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "layout.formfactor.changeFormFactorPatch")
|
||||
|
||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
ListPreference(
|
||||
"revanced_change_form_factor",
|
||||
summaryKey = null,
|
||||
)
|
||||
)
|
||||
|
||||
createPlayerRequestBodyWithModelFingerprint.method.apply {
|
||||
val formFactorEnumClass = formFactorEnumConstructorFingerprint.originalClassDef.type
|
||||
|
||||
val index = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IGET &&
|
||||
reference?.definingClass == formFactorEnumClass &&
|
||||
reference.type == "I"
|
||||
}
|
||||
val register = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||
|
||||
addInstructions(
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.formfactor
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal val formFactorEnumConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||
strings(
|
||||
"UNKNOWN_FORM_FACTOR",
|
||||
"SMALL_FORM_FACTOR",
|
||||
"LARGE_FORM_FACTOR",
|
||||
"AUTOMOTIVE_FORM_FACTOR"
|
||||
)
|
||||
}
|
||||
|
||||
internal val createPlayerRequestBodyWithModelFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("L")
|
||||
parameters()
|
||||
opcodes(Opcode.OR_INT_LIT16)
|
||||
custom { method, _ ->
|
||||
method.indexOfModelInstruction() >= 0 &&
|
||||
method.indexOfReleaseInstruction() >= 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun Method.indexOfModelInstruction() =
|
||||
indexOfFirstInstruction {
|
||||
val reference = getReference<FieldReference>()
|
||||
|
||||
reference?.definingClass == "Landroid/os/Build;" &&
|
||||
reference.name == "MODEL" &&
|
||||
reference.type == "Ljava/lang/String;"
|
||||
}
|
||||
|
||||
internal fun Method.indexOfReleaseInstruction(): Int =
|
||||
indexOfFirstInstruction {
|
||||
val reference = getReference<FieldReference>()
|
||||
|
||||
reference?.definingClass == "Landroid/os/Build${'$'}VERSION;" &&
|
||||
reference.name == "RELEASE" &&
|
||||
reference.type == "Ljava/lang/String;"
|
||||
}
|
||||
|
@ -1,66 +1,9 @@
|
||||
package app.revanced.patches.youtube.layout.tablet
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.layout.formfactor.changeFormFactorPatch
|
||||
|
||||
const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/TabletLayoutPatch;"
|
||||
|
||||
val enableTabletLayoutPatch = bytecodePatch(
|
||||
name = "Enable tablet layout",
|
||||
description = "Adds an option to enable tablet layout.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"18.38.44",
|
||||
"18.49.37",
|
||||
"19.16.39",
|
||||
"19.25.37",
|
||||
"19.34.42",
|
||||
"19.43.41",
|
||||
"19.45.38",
|
||||
"19.46.42",
|
||||
"19.47.53",
|
||||
),
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "layout.tablet.enableTabletLayoutPatch")
|
||||
|
||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
SwitchPreference("revanced_tablet_layout"),
|
||||
)
|
||||
|
||||
getFormFactorFingerprint.method.apply {
|
||||
val returnIsLargeFormFactorIndex = instructions.lastIndex - 4
|
||||
val returnIsLargeFormFactorLabel = getInstruction(returnIsLargeFormFactorIndex)
|
||||
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getTabletLayoutEnabled()Z
|
||||
move-result v0
|
||||
if-nez v0, :is_large_form_factor
|
||||
""",
|
||||
ExternalLabel(
|
||||
"is_large_form_factor",
|
||||
returnIsLargeFormFactorLabel,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Deprecated("Use 'Change form factor' instead.")
|
||||
val enableTabletLayoutPatch = bytecodePatch {
|
||||
dependsOn(changeFormFactorPatch)
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.tablet
|
||||
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val getFormFactorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("L")
|
||||
parameters("Landroid/content/Context;", "Ljava/util/List;")
|
||||
opcodes(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
)
|
||||
strings("")
|
||||
}
|
@ -105,3 +105,15 @@ internal val pivotBarConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
strings("com.google.android.apps.youtube.app.endpoint.flags")
|
||||
}
|
||||
|
||||
internal val imageEnumConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||
strings("TAB_ACTIVITY_CAIRO")
|
||||
}
|
||||
|
||||
internal val setEnumMapFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
literal {
|
||||
ytFillBellId
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.youtube.misc.navigation
|
||||
|
||||
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.instructions
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
@ -12,13 +13,16 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
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.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
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.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@ -26,6 +30,8 @@ internal var imageOnlyTabResourceId = -1L
|
||||
private set
|
||||
internal var actionBarSearchResultsViewMicId = -1L
|
||||
private set
|
||||
internal var ytFillBellId = -1L
|
||||
private set
|
||||
|
||||
private val navigationBarHookResourcePatch = resourcePatch {
|
||||
dependsOn(resourceMappingPatch)
|
||||
@ -33,6 +39,7 @@ private val navigationBarHookResourcePatch = resourcePatch {
|
||||
execute {
|
||||
imageOnlyTabResourceId = resourceMappings["layout", "image_only_tab"]
|
||||
actionBarSearchResultsViewMicId = resourceMappings["layout", "action_bar_search_results_view_mic"]
|
||||
ytFillBellId = resourceMappings["drawable", "yt_fill_bell_black_24"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,6 +151,36 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
||||
)
|
||||
}
|
||||
|
||||
// Fix YT bug of notification tab missing the filled icon.
|
||||
if (is_19_35_or_greater) {
|
||||
val cairoNotificationEnumReference = with(imageEnumConstructorFingerprint) {
|
||||
val stringIndex = stringMatches!!.first().index
|
||||
val cairoNotificationEnumIndex = method.indexOfFirstInstructionOrThrow(stringIndex) {
|
||||
opcode == Opcode.SPUT_OBJECT
|
||||
}
|
||||
method.getInstruction<ReferenceInstruction>(cairoNotificationEnumIndex).reference
|
||||
}
|
||||
|
||||
setEnumMapFingerprint.method.apply {
|
||||
val enumMapIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.definingClass == "Ljava/util/EnumMap;" &&
|
||||
reference.name == "put" &&
|
||||
reference.parameterTypes.firstOrNull() == "Ljava/lang/Enum;"
|
||||
}
|
||||
val instruction = getInstruction<FiveRegisterInstruction>(enumMapIndex)
|
||||
|
||||
addInstructions(
|
||||
enumMapIndex + 1,
|
||||
"""
|
||||
sget-object v${instruction.registerD}, $cairoNotificationEnumReference
|
||||
invoke-static { v${instruction.registerC}, v${instruction.registerD} }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user