diff --git a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt index b1c99a5f6..96762399f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt @@ -306,23 +306,32 @@ internal val repeatTrackFingerprint = legacyFingerprint( strings = listOf("w_st") ) +internal const val SHUFFLE_BUTTON_ID = 45468L + internal val shuffleOnClickFingerprint = legacyFingerprint( name = "shuffleOnClickFingerprint", returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("Landroid/view/View;"), - literals = listOf(45468L), + literals = listOf(SHUFFLE_BUTTON_ID), customFingerprint = { method, _ -> - method.name == "onClick" && - indexOfAccessibilityInstruction(method) >= 0 + method.name == "onClick" } ) -internal fun indexOfAccessibilityInstruction(method: Method) = - method.indexOfFirstInstruction { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "announceForAccessibility" +internal val shuffleEnumFingerprint = legacyFingerprint( + name = "shuffleEnumFingerprint", + returnType = "V", + parameters = emptyList(), + strings = listOf( + "SHUFFLE_OFF", + "SHUFFLE_ALL", + "SHUFFLE_DISABLED", + ), + customFingerprint = { method, _ -> + method.name == "" } +) internal val swipeToCloseFingerprint = legacyFingerprint( name = "swipeToCloseFingerprint", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt index 6f49240a4..c86bf5d52 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt @@ -24,6 +24,7 @@ import app.revanced.patches.music.utils.playservice.is_6_27_or_greater import app.revanced.patches.music.utils.playservice.is_6_42_or_greater import app.revanced.patches.music.utils.playservice.is_7_18_or_greater import app.revanced.patches.music.utils.playservice.is_7_25_or_greater +import app.revanced.patches.music.utils.playservice.is_8_03_or_greater import app.revanced.patches.music.utils.playservice.versionCheckPatch import app.revanced.patches.music.utils.resourceid.colorGrey import app.revanced.patches.music.utils.resourceid.darkBackground @@ -57,6 +58,7 @@ import app.revanced.util.fingerprint.mutableClassOrThrow import app.revanced.util.fingerprint.resolvable import app.revanced.util.getReference import app.revanced.util.getWalkerMethod +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstLiteralInstructionOrThrow @@ -65,6 +67,7 @@ import app.revanced.util.insertNode import app.revanced.util.or 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.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -72,6 +75,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import org.w3c.dom.Element private const val IMAGE_VIEW_TAG_NAME = @@ -850,17 +854,28 @@ val playerComponentsPatch = bytecodePatch( // region patch for remember shuffle state shuffleOnClickFingerprint.methodOrThrow().apply { - val accessibilityIndex = indexOfAccessibilityInstruction(this) - // region set shuffle enum + val enumClass = shuffleEnumFingerprint.methodOrThrow().definingClass - val enumIndex = indexOfFirstInstructionReversedOrThrow(accessibilityIndex) { - opcode == Opcode.INVOKE_DIRECT && - getReference()?.returnType == "Ljava/lang/String;" + val startIndex = indexOfFirstLiteralInstructionOrThrow(SHUFFLE_BUTTON_ID) + + val (enumIndex, enumRegister) = if (is_8_03_or_greater) { + val index = indexOfFirstInstructionReversedOrThrow(startIndex) { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.returnType == enumClass + } + val register = getInstruction(index + 1).registerA + + Pair(index + 2, register) + } else { + val index = indexOfFirstInstructionReversedOrThrow(startIndex) { + opcode == Opcode.INVOKE_DIRECT && + getReference()?.returnType == "Ljava/lang/String;" + } + val register = getInstruction(index).registerD + + Pair(index, register) } - val enumRegister = getInstruction(enumIndex).registerD - val enumClass = - (getInstruction(enumIndex).reference as MethodReference).parameterTypes.first() addInstruction( enumIndex, @@ -872,7 +887,7 @@ val playerComponentsPatch = bytecodePatch( // region set static field val shuffleClassIndex = - indexOfFirstInstructionReversedOrThrow(accessibilityIndex, Opcode.CHECK_CAST) + indexOfFirstInstructionReversedOrThrow(enumIndex, Opcode.CHECK_CAST) val shuffleClass = getInstruction(shuffleClassIndex).reference.toString() val shuffleMutableClass = classBy { classDef -> @@ -901,17 +916,55 @@ val playerComponentsPatch = bytecodePatch( // region make all methods accessible + fun Method.indexOfEnumOrdinalInstruction() = + indexOfFirstInstruction { + val reference = getReference() + opcode == Opcode.INVOKE_VIRTUAL && + reference?.name == "ordinal" && + reference.definingClass == enumClass + } + + val isShuffleMethod: Method.() -> Boolean = { + returnType == "V" && + indexOfEnumOrdinalInstruction() >= 0 && + indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "post" + } >= 0 + } + val shuffleMethod = shuffleMutableClass.methods.find { method -> - method.parameterTypes.firstOrNull() == enumClass && - method.parameterTypes.size == 1 && - method.returnType == "V" + method.isShuffleMethod() } ?: throw PatchException("shuffle method not found") + val shuffleMethodRegisterCount = shuffleMethod.implementation!!.registerCount shuffleMutableClass.methods.add( shuffleMethod.cloneMutable( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - name = "shuffleTracks" - ) + name = "shuffleTracks", + registerCount = if (is_8_03_or_greater) { + shuffleMethodRegisterCount + 1 + } else { + shuffleMethodRegisterCount + }, + parameters = listOf( + ImmutableMethodParameter( + enumClass, + annotations, + "enumClass" + ) + ) + ).apply { + if (is_8_03_or_greater) { + val index = indexOfEnumOrdinalInstruction() + val register = getInstruction(index).registerC + + addInstruction( + index, + "move-object/from16 v$register, p1" + ) + } + } ) // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/compatibility/Constants.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/compatibility/Constants.kt index f7d70c001..a700dcb7d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/compatibility/Constants.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/compatibility/Constants.kt @@ -15,7 +15,7 @@ internal object Constants { "6.51.53", // This is the latest version of YouTube Music 6.xx.xx "7.16.53", // This is the latest version that supports the 'Spoof app version' patch. "7.25.53", // This is the last supported version for 2024. - "8.02.53", // This is the latest version supported by the RVX patch. + "8.05.50", // This is the latest version supported by the RVX patch. ) ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt index f9fcceafd..334d5bdfe 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt @@ -33,6 +33,8 @@ var is_7_27_or_greater = false private set var is_7_29_or_greater = false private set +var is_8_03_or_greater = false + private set val versionCheckPatch = resourcePatch( description = "versionCheckPatch", @@ -62,5 +64,6 @@ val versionCheckPatch = resourcePatch( is_7_25_or_greater = 244399000 <= playStoreServicesVersion is_7_27_or_greater = 244515000 <= playStoreServicesVersion is_7_29_or_greater = 244799000 <= playStoreServicesVersion + is_8_03_or_greater = 250399000 <= playStoreServicesVersion } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt index 1bd5d1bab..9665230b9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt @@ -10,6 +10,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.iface.reference.StringReference internal val createPlayerRequestBodyWithModelFingerprint = legacyFingerprint( name = "createPlayerRequestBodyWithModelFingerprint", @@ -75,9 +76,14 @@ internal val sharedSettingFingerprint = legacyFingerprint( internal val spannableStringBuilderFingerprint = legacyFingerprint( name = "spannableStringBuilderFingerprint", returnType = "Ljava/lang/CharSequence;", - strings = listOf("Failed to set PB Style Run Extension in TextComponentSpec. Extension id: %s"), customFingerprint = { method, _ -> - indexOfSpannableStringInstruction(method) >= 0 + method.indexOfFirstInstruction { + opcode == Opcode.CONST_STRING && + getReference() + ?.string.toString() + .startsWith("Failed to set PB Style Run Extension in TextComponentSpec.") + } >= 0 && + indexOfSpannableStringInstruction(method) >= 0 } ) diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/litho/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/litho/Fingerprints.kt index 1adf981c2..3008532e8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/litho/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/litho/Fingerprints.kt @@ -1,16 +1,21 @@ package app.revanced.patches.shared.litho import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.StringReference + +internal const val BUFFER_UPD_FEATURE_FLAG = 45419603L internal val bufferUpbFeatureFlagFingerprint = legacyFingerprint( name = "bufferUpbFeatureFlagFingerprint", returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("L"), - literals = listOf(45419603L), + literals = listOf(BUFFER_UPD_FEATURE_FLAG), ) internal val byteBufferFingerprint = legacyFingerprint( @@ -51,9 +56,16 @@ internal val emptyComponentsFingerprint = legacyFingerprint( Opcode.INVOKE_INTERFACE, Opcode.INVOKE_STATIC_RANGE, Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT + Opcode.IGET_OBJECT, ), - strings = listOf("Error while converting %s"), + customFingerprint = { method, _ -> + method.indexOfFirstInstruction { + opcode == Opcode.CONST_STRING && + getReference() + ?.string.toString() + .startsWith("Error while converting") + } >= 0 + } ) /** @@ -65,10 +77,12 @@ internal val pathBuilderFingerprint = legacyFingerprint( strings = listOf("Number of bits must be positive"), ) +internal const val PATH_UPD_FEATURE_FLAG = 45631264L + internal val pathUpbFeatureFlagFingerprint = legacyFingerprint( name = "pathUpbFeatureFlagFingerprint", returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = emptyList(), - literals = listOf(45631264L), + literals = listOf(PATH_UPD_FEATURE_FLAG), ) \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/litho/LithoFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/litho/LithoFilterPatch.kt index d517732b1..54767b4da 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/litho/LithoFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/litho/LithoFilterPatch.kt @@ -165,13 +165,11 @@ val lithoFilterPatch = bytecodePatch( // Turn off native code that handles litho component names. If this feature is on then nearly // all litho components have a null name and identifier/path filtering is completely broken. - if (bufferUpbFeatureFlagFingerprint.second.methodOrNull != null && - pathUpbFeatureFlagFingerprint.second.methodOrNull != null - ) { - mapOf( - bufferUpbFeatureFlagFingerprint to 45419603L, - pathUpbFeatureFlagFingerprint to 45631264L, - ).forEach { (fingerprint, literalValue) -> + mapOf( + bufferUpbFeatureFlagFingerprint to BUFFER_UPD_FEATURE_FLAG, + pathUpbFeatureFlagFingerprint to PATH_UPD_FEATURE_FLAG, + ).forEach { (fingerprint, literalValue) -> + if (fingerprint.second.methodOrNull != null) { fingerprint.injectLiteralInstructionBooleanCall( literalValue, "0x0"