From e30f593af02c21fa167f868f52a23c51a339d817 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 11 Apr 2025 21:30:47 +0200 Subject: [PATCH] feat(Spotify): Add limited support for version `8.6.98.900` (last version that supports Kenwood and Pioneer car stereos) (#4750) --- .../useraccount/v1/AccountAttribute.java | 8 ++++++++ .../misc/extension/SharedExtensionPatch.kt | 2 +- .../layout/theme/CustomThemeBytecodePatch.kt | 7 +++++++ .../patches/spotify/misc/Fingerprints.kt | 17 +++++++++++++++-- .../spotify/misc/extension/ExtensionPatch.kt | 17 ++++++++++++++++- .../patches/spotify/misc/extension/Hooks.kt | 11 +++++++++-- 6 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java diff --git a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java new file mode 100644 index 000000000..a03b583bf --- /dev/null +++ b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java @@ -0,0 +1,8 @@ +package com.spotify.useraccount.v1; + +/** + * Used for target 8.6.98.900. Class is still present in newer app targets. + */ +public class AccountAttribute { + public Object value_; +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt index 5233f186f..40ced06a0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt @@ -92,7 +92,7 @@ fun sharedExtensionPatch( } class ExtensionHook internal constructor( - private val fingerprint: Fingerprint, + internal val fingerprint: Fingerprint, private val insertIndexResolver: ((Method) -> Int), private val contextRegisterResolver: (Method) -> String, ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt index cdedbfd6a..2f639ef8d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch import app.revanced.util.* import com.android.tools.smali.dexlib2.AccessFlags @@ -21,6 +22,12 @@ internal val customThemeByteCodePatch = bytecodePatch { val backgroundColorSecondary by spotifyBackgroundColorSecondary execute { + if (IS_SPOTIFY_LEGACY_APP_TARGET) { + // Bytecode changes are not needed for legacy app target. + // Player background color is changed with existing resource patch. + return@execute + } + fun MutableMethod.addColorChangeInstructions(literal: Long, colorString: String) { val index = indexOfFirstLiteralInstructionOrThrow(literal) val register = getInstruction(index).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index b23f405f4..29f472a5d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -1,16 +1,29 @@ package app.revanced.patches.spotify.misc import app.revanced.patcher.fingerprint +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode internal val accountAttributeFingerprint = fingerprint { - custom { _, classDef -> classDef.endsWith("internal/AccountAttribute;") } + custom { _, classDef -> + classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) { + "Lcom/spotify/useraccount/v1/AccountAttribute;" + } else { + "Lcom/spotify/remoteconfig/internal/AccountAttribute;" + } + } } internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") - custom { _, classDef -> classDef.endsWith("ProductStateProto;") } + custom { _, classDef -> + classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) { + "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" + } else { + "Lcom/spotify/remoteconfig/internal/ProductStateProto;" + } + } } internal val buildQueryParametersFingerprint = fingerprint { diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt index 6b95f437a..98afe65b2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt @@ -1,5 +1,20 @@ package app.revanced.patches.spotify.misc.extension +import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch -val sharedExtensionPatch = sharedExtensionPatch("spotify", spotifyMainActivityOnCreate) +/** + * If patching a legacy 8.x target. This may also be set if patching slightly older/newer app targets, + * but the only legacy target of interest is 8.6.98.900 as it's the last version that + * supports Spotify integration on Kenwood/Pioneer car stereos. + */ +internal var IS_SPOTIFY_LEGACY_APP_TARGET = false + +val sharedExtensionPatch = bytecodePatch { + dependsOn(sharedExtensionPatch("spotify", spotifyMainActivityOnCreate)) + + execute { + IS_SPOTIFY_LEGACY_APP_TARGET = spotifyMainActivityOnCreate.fingerprint + .originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt index baed926ea..956c5610e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt @@ -2,9 +2,16 @@ package app.revanced.patches.spotify.misc.extension import app.revanced.patches.shared.misc.extension.extensionHook +private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;" + +/** + * Main activity of target 8.6.98.900. + */ +internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivity;" + internal val spotifyMainActivityOnCreate = extensionHook { custom { method, classDef -> - classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" && - method.name == "onCreate" + method.name == "onCreate" && (classDef.type == SPOTIFY_MAIN_ACTIVITY + || classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY) } }