fix(YouTube - Theme): Use custom seekbar color for cairo startup animation (#4399)

This commit is contained in:
LisoUseInAIKyrios
2025-02-02 11:10:57 +02:00
committed by GitHub
parent 8891f98511
commit 1cba2948a6
4 changed files with 254 additions and 13 deletions

View File

@ -2,9 +2,12 @@ package app.revanced.patches.youtube.layout.seekbar
import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val fullscreenSeekbarThumbnailsFingerprint = fingerprint {
returns("Z")
@ -109,3 +112,52 @@ internal val launchScreenLayoutTypeFingerprint = fingerprint {
&& method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag)
}
}
internal const val LOTTIE_ANIMATION_VIEW_CLASS_TYPE = "Lcom/airbnb/lottie/LottieAnimationView;"
internal val lottieAnimationViewSetAnimationIntFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("I")
returns("V")
custom { methodDef, classDef ->
classDef.type == LOTTIE_ANIMATION_VIEW_CLASS_TYPE && methodDef.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.definingClass == "Lcom/airbnb/lottie/LottieAnimationView;"
&& reference.name == "isInEditMode"
} >= 0
}
}
internal val lottieAnimationViewSetAnimationStreamFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("L")
returns("V")
custom { methodDef, classDef ->
classDef.type == LOTTIE_ANIMATION_VIEW_CLASS_TYPE && methodDef.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.definingClass == "Ljava/util/Set;"
&& reference.name == "add"
} >= 0 && methodDef.containsLiteralInstruction(0)
}
}
internal val lottieCompositionFactoryZipFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
parameters("Landroid/content/Context;", "Ljava/lang/String;", "Ljava/lang/String;")
returns("L")
strings(".zip", ".lottie")
}
/**
* Resolves using class found in [lottieCompositionFactoryZipFingerprint].
*
* [Original method](https://github.com/airbnb/lottie-android/blob/26ad8bab274eac3f93dccccfa0cafc39f7408d13/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java#L386)
*/
internal val lottieCompositionFactoryFromJsonInputStreamFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
parameters("Ljava/io/InputStream;", "Ljava/lang/String;")
returns("L")
literal { 2 }
}

View File

@ -3,10 +3,12 @@ package app.revanced.patches.youtube.layout.seekbar
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.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
@ -22,15 +24,21 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertFeatureFlagBooleanOverride
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import org.w3c.dom.Element
import java.io.ByteArrayInputStream
import kotlin.use
@ -307,7 +315,11 @@ val seekbarColorPatch = bytecodePatch(
// region apply seekbar custom color to splash screen animation.
// Don't use the lotte splash screen layout if using custom seekbar.
if (!is_19_34_or_greater) {
return@execute // 19.25 does not have a cairo launch animation.
}
// Add development hook to force old drawable splash animation.
arrayOf(
launchScreenLayoutTypeFingerprint,
mainActivityOnCreateFingerprint
@ -318,7 +330,7 @@ val seekbarColorPatch = bytecodePatch(
)
}
// Hook the splash animation drawable to set the a seekbar color theme.
// Hook the splash animation to set the a seekbar color.
mainActivityOnCreateFingerprint.method.apply {
val drawableIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
@ -333,6 +345,87 @@ val seekbarColorPatch = bytecodePatch(
"invoke-static { v$drawableRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setSplashAnimationDrawableTheme(Landroid/graphics/drawable/AnimatedVectorDrawable;)V"
)
// Replace the Lottie animation view setAnimation(int) call.
val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name
findInstructionIndicesReversedOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Lcom/airbnb/lottie/LottieAnimationView;"
&& reference.name == setAnimationIntMethodName
}.forEach { index ->
val instruction = getInstruction<FiveRegisterInstruction>(index)
replaceInstruction(
index,
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" +
"(Lcom/airbnb/lottie/LottieAnimationView;I)V"
)
}
}
// Add non obfuscated method aliases for `setAnimation(int)`
// and `setAnimation(InputStream, String)` so extension code can call them.
lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply {
val addedMethodName = "patch_setAnimation"
val setAnimationIntName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name
add(ImmutableMethod(
LOTTIE_ANIMATION_VIEW_CLASS_TYPE,
addedMethodName,
listOf(ImmutableMethodParameter("I", null, null)),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(2),
).toMutable().apply {
addInstructions(
"""
invoke-virtual { p0, p1 }, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationIntName(I)V
return-void
"""
)
})
val factoryStreamClass : CharSequence
val factoryStreamName : CharSequence
val factoryStreamReturnType : CharSequence
lottieCompositionFactoryFromJsonInputStreamFingerprint.match(
lottieCompositionFactoryZipFingerprint.originalClassDef
).originalMethod.apply {
factoryStreamClass = definingClass
factoryStreamName = name
factoryStreamReturnType = returnType
}
val setAnimationStreamName = lottieAnimationViewSetAnimationStreamFingerprint
.originalMethod.name
add(ImmutableMethod(
LOTTIE_ANIMATION_VIEW_CLASS_TYPE,
addedMethodName,
listOf(
ImmutableMethodParameter("Ljava/io/InputStream;", null, null),
ImmutableMethodParameter("Ljava/lang/String;", null, null)
),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-static { p1, p2 }, $factoryStreamClass->$factoryStreamName(Ljava/io/InputStream;Ljava/lang/String;)$factoryStreamReturnType
move-result-object v0
invoke-virtual { p0, v0}, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationStreamName($factoryStreamReturnType)V
return-void
"""
)
})
}
// endregion