Skip to content

Commit e7dd061

Browse files
authored
fix(Spotify): Fix Hide Create button and Sanitize sharing links for older but supported app targets (#5159)
1 parent 756b28d commit e7dd061

File tree

5 files changed

+72
-40
lines changed

5 files changed

+72
-40
lines changed

extensions/spotify/src/main/java/app/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,24 @@ public static Object returnNullIfIsCreateButton(Object navigationBarItem) {
3737
return null;
3838
}
3939

40-
String stringifiedNavigationBarItem = navigationBarItem.toString();
40+
try {
41+
String stringifiedNavigationBarItem = navigationBarItem.toString();
4142

42-
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
43-
if (componentFilter.filterUnavailable()) {
44-
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
45-
componentFilter.getFilterRepresentation() + " not available, skipping");
46-
continue;
47-
}
43+
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
44+
if (componentFilter.filterUnavailable()) {
45+
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
46+
componentFilter.getFilterRepresentation() + " not available, skipping");
47+
continue;
48+
}
4849

49-
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
50-
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
51-
" matched the filter " + componentFilter.getFilterRepresentation());
52-
return null;
50+
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
51+
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " +
52+
navigationBarItem + " matched the filter " + componentFilter.getFilterRepresentation());
53+
return null;
54+
}
5355
}
56+
} catch (Exception ex) {
57+
Logger.printException(() -> "returnNullIfIsCreateButton failure", ex);
5458
}
5559

5660
return navigationBarItem;

extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -202,37 +202,41 @@ public static boolean isFilteredContextMenuItem(Object contextMenuItem) {
202202
return false;
203203
}
204204

205-
String stringifiedContextMenuItem = contextMenuItem.toString();
205+
try {
206+
String stringifiedContextMenuItem = contextMenuItem.toString();
206207

207-
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
208-
boolean allMatch = true;
209-
StringBuilder matchedFilterRepresentations = new StringBuilder();
208+
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
209+
boolean allMatch = true;
210+
StringBuilder matchedFilterRepresentations = new StringBuilder();
210211

211-
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
212-
ComponentFilter componentFilter = componentFilters.get(i);
212+
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
213+
ComponentFilter componentFilter = componentFilters.get(i);
213214

214-
if (componentFilter.filterUnavailable()) {
215-
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
216-
componentFilter.getFilterRepresentation() + " not available, skipping");
217-
continue;
218-
}
215+
if (componentFilter.filterUnavailable()) {
216+
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
217+
componentFilter.getFilterRepresentation() + " not available, skipping");
218+
continue;
219+
}
219220

220-
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
221-
allMatch = false;
222-
break;
223-
}
221+
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
222+
allMatch = false;
223+
break;
224+
}
224225

225-
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
226-
if (i < filterSize - 1) {
227-
matchedFilterRepresentations.append(", ");
226+
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
227+
if (i < filterSize - 1) {
228+
matchedFilterRepresentations.append(", ");
229+
}
228230
}
229-
}
230231

231-
if (allMatch) {
232-
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
233-
" because the following filters matched: " + matchedFilterRepresentations);
234-
return true;
232+
if (allMatch) {
233+
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
234+
" because the following filters matched: " + matchedFilterRepresentations);
235+
return true;
236+
}
235237
}
238+
} catch (Exception ex) {
239+
Logger.printException(() -> "isFilteredContextMenuItem failure", ex);
236240
}
237241

238242
return false;

patches/src/main/kotlin/app/revanced/patches/spotify/layout/hide/createbutton/HideCreateButtonPatch.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ val hideCreateButtonPatch = bytecodePatch(
7272

7373
if (oldNavigationBarAddItemMethod != null) {
7474
// In case an older version of the app is being patched, hook the old method which adds navigation bar items.
75-
// Return null early if the navigation bar item title resource id is the old Create button title resource id.
75+
// Return early if the navigation bar item title resource id is the old Create button title resource id.
7676
oldNavigationBarAddItemFingerprint.methodOrNull?.apply {
7777
val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow {
7878
val reference = getReference<MethodReference>()
@@ -89,6 +89,16 @@ val hideCreateButtonPatch = bytecodePatch(
8989
val isOldCreateButtonDescriptor =
9090
"$EXTENSION_CLASS_DESCRIPTOR->isOldCreateButton(I)Z"
9191

92+
val returnEarlyInstruction = if (returnType == "V") {
93+
// In older implementations the method return value is void.
94+
"return-void"
95+
} else {
96+
// In newer implementations
97+
// return null because the method return value is a BottomNavigationItemView.
98+
"const/4 v0, 0\n" +
99+
"return-object v0"
100+
}
101+
92102
addInstructionsWithLabels(
93103
0,
94104
"""
@@ -98,9 +108,7 @@ val hideCreateButtonPatch = bytecodePatch(
98108
# If this navigation bar item is not the Create button, jump to the normal method logic.
99109
if-eqz v0, :normal-method-logic
100110
101-
# Return null early because this method return value is a BottomNavigationItemView.
102-
const/4 v0, 0
103-
return-object v0
111+
$returnEarlyInstruction
104112
""",
105113
ExternalLabel("normal-method-logic", firstInstruction)
106114
)

patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/Fingerprints.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package app.revanced.patches.spotify.misc.privacy
33
import app.revanced.patcher.fingerprint
44
import app.revanced.util.literal
55
import com.android.tools.smali.dexlib2.AccessFlags
6+
import com.android.tools.smali.dexlib2.Opcode
67

78
internal val shareCopyUrlFingerprint = fingerprint {
89
returns("Ljava/lang/Object;")
@@ -23,9 +24,15 @@ internal val shareCopyUrlLegacyFingerprint = fingerprint {
2324
}
2425

2526
internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
26-
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
2727
returns("Ljava/lang/String;")
2828
parameters("L", "Ljava/lang/String;")
29+
opcodes(
30+
Opcode.GOTO,
31+
Opcode.IF_EQZ,
32+
Opcode.INVOKE_STATIC,
33+
Opcode.MOVE_RESULT_OBJECT,
34+
Opcode.RETURN_OBJECT
35+
)
2936
literal {
3037
'\n'.code.toLong()
3138
}

patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/SanitizeSharingLinksPatch.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
88
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
99
import app.revanced.util.getReference
1010
import app.revanced.util.indexOfFirstInstructionOrThrow
11+
import com.android.tools.smali.dexlib2.AccessFlags
1112
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
1213
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
1314

@@ -56,7 +57,15 @@ val sanitizeSharingLinksPatch = bytecodePatch(
5657
shareUrlParameter = "p2"
5758
} else {
5859
shareSheetFingerprint = formatAndroidShareSheetUrlFingerprint
59-
shareUrlParameter = "p1"
60+
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod.accessFlags
61+
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags)) {
62+
// In newer implementations the method is static, so p0 is not `this`.
63+
"p1"
64+
} else {
65+
// In older implementations the method is not static, making it so p0 is `this`.
66+
// For that reason, add one to the parameter register.
67+
"p2"
68+
}
6069
}
6170

6271
shareSheetFingerprint.method.addInstructions(

0 commit comments

Comments
 (0)