diff --git a/CHANGELOG.md b/CHANGELOG.md
index b85e438ac..a7b15246d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)
+
+
+### Features
+
+* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
+
+## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)
+
+
+### Bug Fixes
+
+* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
+
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)
diff --git a/extensions/samsung/radio/build.gradle.kts b/extensions/samsung/radio/build.gradle.kts
new file mode 100644
index 000000000..0eadeef26
--- /dev/null
+++ b/extensions/samsung/radio/build.gradle.kts
@@ -0,0 +1,4 @@
+dependencies {
+ compileOnly(project(":extensions:shared:library"))
+ compileOnly(project(":extensions:samsung:radio:stub"))
+}
diff --git a/extensions/samsung/radio/src/main/AndroidManifest.xml b/extensions/samsung/radio/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..9b65eb06c
--- /dev/null
+++ b/extensions/samsung/radio/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch.java b/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch.java
new file mode 100644
index 000000000..72c5addc4
--- /dev/null
+++ b/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch.java
@@ -0,0 +1,24 @@
+package app.revanced.extension.samsung.radio.misc.fix.crash;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public final class FixCrashPatch {
+ /**
+ * Injection point.
+ *
+ * Add the required permissions to the request list to avoid crashes on API 34+.
+ **/
+ public static final String[] fixPermissionRequestList(String[] perms) {
+ List permsList = new ArrayList<>(Arrays.asList(perms));
+ if (permsList.contains("android.permission.POST_NOTIFICATIONS")) {
+ permsList.addAll(Arrays.asList("android.permission.RECORD_AUDIO", "android.permission.READ_PHONE_STATE", "android.permission.FOREGROUND_SERVICE_MICROPHONE"));
+ }
+ if (permsList.contains("android.permission.RECORD_AUDIO")) {
+ permsList.add("android.permission.FOREGROUND_SERVICE_MICROPHONE");
+ }
+ return permsList.toArray(new String[0]);
+ }
+}
diff --git a/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch.java b/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch.java
new file mode 100644
index 000000000..19b6c3e82
--- /dev/null
+++ b/extensions/samsung/radio/src/main/java/app/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch.java
@@ -0,0 +1,19 @@
+package app.revanced.extension.samsung.radio.restrictions.device;
+
+import android.os.SemSystemProperties;
+
+import java.util.Arrays;
+
+@SuppressWarnings("unused")
+public final class BypassDeviceChecksPatch {
+
+ /**
+ * Injection point.
+ *
+ * Check if the device has the required hardware
+ **/
+ public static final boolean checkIfDeviceIsIncompatible(String[] deviceList) {
+ String currentDevice = SemSystemProperties.getSalesCode();
+ return Arrays.asList(deviceList).contains(currentDevice);
+ }
+}
diff --git a/extensions/samsung/radio/stub/build.gradle.kts b/extensions/samsung/radio/stub/build.gradle.kts
new file mode 100644
index 000000000..b4bee8809
--- /dev/null
+++ b/extensions/samsung/radio/stub/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ alias(libs.plugins.android.library)
+}
+
+android {
+ namespace = "app.revanced.extension"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 24
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
diff --git a/extensions/samsung/radio/stub/src/main/AndroidManifest.xml b/extensions/samsung/radio/stub/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..15e7c2ae6
--- /dev/null
+++ b/extensions/samsung/radio/stub/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/extensions/samsung/radio/stub/src/main/java/android/os/SemSystemProperties.java b/extensions/samsung/radio/stub/src/main/java/android/os/SemSystemProperties.java
new file mode 100644
index 000000000..33a4b4400
--- /dev/null
+++ b/extensions/samsung/radio/stub/src/main/java/android/os/SemSystemProperties.java
@@ -0,0 +1,7 @@
+package android.os;
+
+public class SemSystemProperties {
+ public static String getSalesCode() {
+ throw new UnsupportedOperationException("Stub");
+ }
+}
\ No newline at end of file
diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java
index a9fbe8f7f..d9185ba35 100644
--- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java
+++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java
@@ -88,7 +88,8 @@ public final class LayoutComponentsFilter extends Filter {
"post_shelf_slim.e",
"videos_post_responsive_root.e",
"text_post_responsive_root.e",
- "poll_post_responsive_root.e"
+ "poll_post_responsive_root.e",
+ "shared_post_root.e"
);
final var subscribersCommunityGuidelines = new StringFilterGroup(
diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/ProgressBarDrawable.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/ProgressBarDrawable.java
deleted file mode 100644
index 93d53c9a5..000000000
--- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/ProgressBarDrawable.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package app.revanced.extension.youtube.patches.theme;
-
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import app.revanced.extension.youtube.patches.HideSeekbarPatch;
-import app.revanced.extension.youtube.settings.Settings;
-
-/**
- * Used by {@link SeekbarColorPatch} change the color of the seekbar.
- * and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history.
- */
-@SuppressWarnings("unused")
-public class ProgressBarDrawable extends Drawable {
-
- private final Paint paint = new Paint();
- {
- paint.setColor(SeekbarColorPatch.getSeekbarColor());
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) {
- return;
- }
-
- canvas.drawRect(getBounds(), paint);
- }
-
- @Override
- public void setAlpha(int alpha) {
- paint.setAlpha(alpha);
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- paint.setColorFilter(colorFilter);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
-}
diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java
index de70304bb..65f31d813 100644
--- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java
+++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java
@@ -4,9 +4,7 @@ import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.clamp;
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
-import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.drawable.AnimatedVectorDrawable;
import com.airbnb.lottie.LottieAnimationView;
@@ -15,7 +13,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.Locale;
import java.util.Scanner;
import app.revanced.extension.shared.Logger;
@@ -105,27 +102,6 @@ public final class SeekbarColorPatch {
return customSeekbarColor;
}
- private static int colorChannelTo3Bits(int channel8Bits) {
- final float channel3Bits = channel8Bits * 7 / 255f;
-
- // If a color channel is near zero, then allow rounding up so values between
- // 0x12 and 0x23 will show as 0x24. But always round down when the channel is
- // near full saturation, otherwise rounding to nearest will cause all values
- // between 0xEC and 0xFE to always show as full saturation (0xFF).
- return channel3Bits < 6
- ? Math.round(channel3Bits)
- : (int) channel3Bits;
- }
-
- @SuppressWarnings("SameParameterValue")
- private static String get9BitStyleIdentifier(int color24Bit) {
- final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
- final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
- final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
-
- return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
- }
-
/**
* injection point.
*/
@@ -136,36 +112,6 @@ public final class SeekbarColorPatch {
return original; // false = drawable style, true = lottie style.
}
- /**
- * Injection point.
- * Old drawable style launch screen.
- */
- public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
- // Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
- // without using any styles, but a color filter cannot selectively change the seekbar
- // while keeping the red YT logo untouched.
- // Even if the seekbar color xml value is changed to a completely different color (such as green),
- // a color filter still cannot be selectively applied when the drawable has more than 1 color.
- try {
- // Must set the color even if custom seekbar is off,
- // because the xml color was replaced with a themed value.
- String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor);
- Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
-
- final int styleIdentifierDefault = Utils.getResourceIdentifierOrThrow(
- ResourceType.STYLE,
- seekbarStyle
- );
-
- Resources.Theme theme = Utils.getContext().getResources().newTheme();
- theme.applyStyle(styleIdentifierDefault, true);
-
- vectorDrawable.applyTheme(theme);
- } catch (Exception ex) {
- Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
- }
- }
-
/**
* Injection point.
* Modern Lottie style animation.
diff --git a/gradle.properties b/gradle.properties
index 973dda541..a5b833989 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
org.gradle.parallel = true
android.useAndroidX = true
kotlin.code.style = official
-version = 5.43.2-dev.2
+version = 5.44.0-dev.1
diff --git a/patches/api/patches.api b/patches/api/patches.api
index 919a9d487..82c7b524f 100644
--- a/patches/api/patches.api
+++ b/patches/api/patches.api
@@ -714,6 +714,14 @@ public final class app/revanced/patches/reddit/misc/tracking/url/SanitizeUrlQuer
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
+public final class app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatchKt {
+ public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
+}
+
+public final class app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatchKt {
+ public static final fun getBypassDeviceChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
+}
+
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
diff --git a/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/AddManifestPermissionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/AddManifestPermissionsPatch.kt
new file mode 100644
index 000000000..35641f2e7
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/AddManifestPermissionsPatch.kt
@@ -0,0 +1,34 @@
+package app.revanced.patches.samsung.radio.misc.fix.crash
+
+import app.revanced.patcher.patch.resourcePatch
+import app.revanced.util.asSequence
+import org.w3c.dom.Element
+
+@Suppress("unused")
+internal val addManifestPermissionsPatch = resourcePatch {
+
+ val requiredPermissions = listOf(
+ "android.permission.READ_PHONE_STATE",
+ "android.permission.FOREGROUND_SERVICE_MICROPHONE",
+ "android.permission.RECORD_AUDIO",
+ )
+
+ execute {
+ document("AndroidManifest.xml").use { document ->
+ document.getElementsByTagName("manifest").item(0).let { manifestEl ->
+
+ // Check which permissions are missing
+ val existingPermissionNames = document.getElementsByTagName("uses-permission").asSequence()
+ .mapNotNull { (it as? Element)?.getAttribute("android:name") }.toSet()
+ val missingPermissions = requiredPermissions.filterNot { it in existingPermissionNames }
+
+ // Then add them
+ for (permission in missingPermissions) {
+ val element = document.createElement("uses-permission")
+ element.setAttribute("android:name", permission)
+ manifestEl.appendChild(element)
+ }
+ }
+ }
+ }
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/Fingerprints.kt
new file mode 100644
index 000000000..cefa1ce32
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/Fingerprints.kt
@@ -0,0 +1,12 @@
+package app.revanced.patches.samsung.radio.misc.fix.crash
+
+import app.revanced.patcher.fingerprint
+
+internal val permissionRequestListFingerprint by fingerprint {
+ strings(
+ "android.permission.POST_NOTIFICATIONS",
+ "android.permission.READ_MEDIA_AUDIO",
+ "android.permission.RECORD_AUDIO"
+ )
+ custom { method, _ -> method.name == "" }
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatch.kt b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatch.kt
new file mode 100644
index 000000000..a076ca830
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatch.kt
@@ -0,0 +1,42 @@
+@file:Suppress("unused")
+
+package app.revanced.patches.samsung.radio.misc.fix.crash
+
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.patch.bytecodePatch
+import app.revanced.patches.samsung.radio.restrictions.device.bypassDeviceChecksPatch
+import app.revanced.util.findInstructionIndicesReversedOrThrow
+import app.revanced.util.indexOfFirstInstruction
+import com.android.tools.smali.dexlib2.Opcode
+import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
+
+private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch;"
+
+val fixCrashPatch = bytecodePatch(
+ name = "Fix crashes", description = "Prevents the app from crashing because of missing system permissions."
+) {
+ dependsOn(addManifestPermissionsPatch, bypassDeviceChecksPatch)
+ extendWith("extensions/samsung/radio.rve")
+ compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
+
+ execute {
+ permissionRequestListFingerprint.method.apply {
+ findInstructionIndicesReversedOrThrow(Opcode.FILLED_NEW_ARRAY).forEach { filledNewArrayIndex ->
+ val moveResultIndex = indexOfFirstInstruction(filledNewArrayIndex, Opcode.MOVE_RESULT_OBJECT)
+ if (moveResultIndex < 0) return@forEach // No move-result-object found after the filled-new-array
+
+ // Get the register where the array is saved
+ val arrayRegister = getInstruction(moveResultIndex).registerA
+
+ // Invoke the method from the extension
+ addInstructions(
+ moveResultIndex + 1, """
+ invoke-static { v$arrayRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->fixPermissionRequestList([Ljava/lang/String;)[Ljava/lang/String;
+ move-result-object v$arrayRegister
+ """
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatch.kt b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatch.kt
new file mode 100644
index 000000000..6a1ae6551
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatch.kt
@@ -0,0 +1,55 @@
+package app.revanced.patches.samsung.radio.restrictions.device
+
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
+import app.revanced.patcher.patch.bytecodePatch
+import app.revanced.util.findFreeRegister
+import app.revanced.util.getReference
+import app.revanced.util.indexOfFirstInstructionOrThrow
+import com.android.tools.smali.dexlib2.Opcode
+import com.android.tools.smali.dexlib2.iface.reference.StringReference
+
+private const val EXTENSION_CLASS_DESCRIPTOR =
+ "Lapp/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch;"
+
+@Suppress("unused")
+val bypassDeviceChecksPatch = bytecodePatch(
+ name = "Bypass device checks",
+ description = "Removes firmware and region blacklisting. " +
+ "This patch will still not allow the app to run on devices that do not have the required hardware.",
+) {
+ extendWith("extensions/samsung/radio.rve")
+ compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
+
+ execute {
+ // Return false = The device is not blacklisted.
+ checkDeviceFingerprint.method.apply {
+ // Find the first string that start with "SM-", that's the list of incompatible devices.
+ val firstStringIndex = indexOfFirstInstructionOrThrow {
+ opcode == Opcode.CONST_STRING &&
+ getReference()?.string?.startsWith("SM-") == true
+ }
+
+ // Find the following filled-new-array (or filled-new-array/range) instruction.
+ val filledNewArrayIndex = indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
+ opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
+ }
+
+ val resultRegister = findFreeRegister(filledNewArrayIndex + 1)
+
+ // Store the array there and invoke the method that we added to the class earlier.
+ addInstructions(
+ filledNewArrayIndex + 1,
+ """
+ move-result-object v$resultRegister
+ invoke-static { v$resultRegister }, $EXTENSION_CLASS_DESCRIPTOR->checkIfDeviceIsIncompatible([Ljava/lang/String;)Z
+ move-result v$resultRegister
+ return v$resultRegister
+ """
+ )
+
+ // Remove the instructions before our strings.
+ removeInstructions(0, firstStringIndex)
+ }
+ }
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/Fingerprints.kt
new file mode 100644
index 000000000..e5278adee
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/samsung/radio/restrictions/device/Fingerprints.kt
@@ -0,0 +1,61 @@
+package app.revanced.patches.samsung.radio.restrictions.device
+
+import app.revanced.patcher.fingerprint
+import app.revanced.patches.all.misc.transformation.IMethodCall
+import app.revanced.patches.all.misc.transformation.fromMethodReference
+import app.revanced.util.getReference
+import com.android.tools.smali.dexlib2.iface.reference.MethodReference
+
+internal val checkDeviceFingerprint by fingerprint {
+ returns("Z")
+ custom { method, _ ->
+ /* Check for methods call to:
+ - Landroid/os/SemSystemProperties;->getSalesCode()Ljava/lang/String;
+ - Landroid/os/SemSystemProperties;->getCountryIso()Ljava/lang/String;
+ */
+
+ val impl = method.implementation ?: return@custom false
+
+ // Track which target methods we've found
+ val foundMethods = mutableSetOf()
+
+ // Scan method instructions for calls to our target methods
+ for (instr in impl.instructions) {
+ val ref = instr.getReference() ?: continue
+ val mc = fromMethodReference(ref) ?: continue
+
+ if (mc == MethodCall.GetSalesCode || mc == MethodCall.GetCountryIso) {
+ foundMethods.add(mc)
+
+ // If we found both methods, return success
+ if (foundMethods.size == 2) {
+ return@custom true
+ }
+ }
+ }
+
+ // Only match if both methods are present
+ return@custom false
+ }
+}
+
+// Information about method calls we want to replace
+private enum class MethodCall(
+ override val definedClassName: String,
+ override val methodName: String,
+ override val methodParams: Array,
+ override val returnType: String,
+) : IMethodCall {
+ GetSalesCode(
+ "Landroid/os/SemSystemProperties;",
+ "getSalesCode",
+ arrayOf(),
+ "Ljava/lang/String;",
+ ),
+ GetCountryIso(
+ "Landroid/os/SemSystemProperties;",
+ "getCountryIso",
+ arrayOf(),
+ "Ljava/lang/String;",
+ )
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt
index f0dda3446..518e22bfc 100644
--- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt
@@ -1,14 +1,11 @@
package app.revanced.patches.youtube.layout.seekbar
import app.revanced.patcher.Fingerprint
-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.fingerprint
-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.layout.theme.lithoColorHookPatch
@@ -16,21 +13,15 @@ import app.revanced.patches.shared.layout.theme.lithoColorOverrideHook
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
-import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_30_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_34_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
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.inputStreamFromBundledResource
import app.revanced.util.insertLiteralOverride
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
@@ -38,125 +29,6 @@ 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
-
-private const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
-
-private val seekbarColorResourcePatch = resourcePatch {
- dependsOn(
- resourceMappingPatch,
- versionCheckPatch,
- )
-
- execute {
- // Modify the resume playback drawable and replace the progress bar with a custom drawable.
- document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
- val layerList = document.getElementsByTagName("layer-list").item(0) as Element
- val progressNode = layerList.getElementsByTagName("item").item(1) as Element
- if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
- throw PatchException("Could not find progress bar")
- }
- val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element
- val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element
- val replacementNode = document.createElement(
- "app.revanced.extension.youtube.patches.theme.ProgressBarDrawable",
- )
- scaleNode.replaceChild(replacementNode, shapeNode)
- }
-
- // Add attribute and styles for splash screen custom color.
- // Using a style is the only way to selectively change just the seekbar fill color.
- //
- // Because the style colors must be hard coded for all color possibilities,
- // instead of allowing 24 bit color the style is restricted to 9-bit (3 bits per color channel)
- // and the style color closest to the users custom color is used for the splash screen.
- arrayOf(
- inputStreamFromBundledResource("seekbar/values", "attrs.xml")!! to "res/values/attrs.xml",
- ByteArrayInputStream(create9BitSeekbarColorStyles().toByteArray()) to "res/values/styles.xml"
- ).forEach { (source, destination) ->
- "resources".copyXmlNode(
- document(source),
- document(destination),
- ).close()
- }
-
- fun setSplashDrawablePathFillColor(xmlFileNames: Iterable, vararg resourceNames: String) {
- xmlFileNames.forEach { xmlFileName ->
- document(xmlFileName).use { document ->
- val childNodes = document.childNodes
-
- resourceNames.forEach { elementId ->
- val element = childNodes.findElementByAttributeValueOrThrow(
- "android:name",
- elementId
- )
-
- val attribute = "android:fillColor"
- if (!element.hasAttribute(attribute)) {
- throw PatchException("Could not find $attribute for $elementId")
- }
-
- element.setAttribute(attribute, "?attr/$splashSeekbarColorAttributeName")
- }
- }
- }
- }
-
- setSplashDrawablePathFillColor(
- listOf(
- "res/drawable/\$startup_animation_light__0.xml",
- "res/drawable/\$startup_animation_dark__0.xml"
- ),
- "_R_G_L_10_G_D_0_P_0"
- )
-
- if (!is_19_46_or_greater) {
- // Resources removed in 19.46+
- setSplashDrawablePathFillColor(
- listOf(
- "res/drawable/\$buenos_aires_animation_light__0.xml",
- "res/drawable/\$buenos_aires_animation_dark__0.xml"
- ),
- "_R_G_L_8_G_D_0_P_0"
- )
- }
- }
-}
-
-/**
- * Generate a style xml with all combinations of 9-bit colors.
- */
-private fun create9BitSeekbarColorStyles(): String = StringBuilder().apply {
- append("")
- append("\n")
-
- for (red in 0..7) {
- for (green in 0..7) {
- for (blue in 0..7) {
- val name = "${red}_${green}_${blue}"
-
- fun roundTo3BitHex(channel8Bits: Int) =
- (channel8Bits * 255 / 7).toString(16).padStart(2, '0')
- val r = roundTo3BitHex(red)
- val g = roundTo3BitHex(green)
- val b = roundTo3BitHex(blue)
- val color = "#ff$r$g$b"
-
- append(
- """
-
- """
- )
- }
- }
- }
-
- append("")
-}.toString()
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;"
@@ -166,7 +38,6 @@ val seekbarColorPatch = bytecodePatch(
dependsOn(
sharedExtensionPatch,
lithoColorHookPatch,
- seekbarColorResourcePatch,
resourceMappingPatch,
versionCheckPatch
)
@@ -300,21 +171,6 @@ val seekbarColorPatch = bytecodePatch(
// Hook the splash animation to set the a seekbar color.
mainActivityOnCreateFingerprint.method.apply {
- val drawableIndex = indexOfFirstInstructionOrThrow {
- val reference = getReference()
- reference?.definingClass == "Landroid/widget/ImageView;"
- && reference.name == "getDrawable"
- }
- val checkCastIndex = indexOfFirstInstructionOrThrow(drawableIndex, Opcode.CHECK_CAST)
- val drawableRegister = getInstruction(checkCastIndex).registerA
-
- addInstruction(
- checkCastIndex + 1,
- "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
@@ -328,8 +184,7 @@ val seekbarColorPatch = bytecodePatch(
replaceInstruction(
index,
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
- "$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" +
- "(Lcom/airbnb/lottie/LottieAnimationView;I)V"
+ "$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie(Lcom/airbnb/lottie/LottieAnimationView;I)V"
)
}
}
diff --git a/patches/src/main/resources/seekbar/values/attrs.xml b/patches/src/main/resources/seekbar/values/attrs.xml
deleted file mode 100644
index 2bf349f0d..000000000
--- a/patches/src/main/resources/seekbar/values/attrs.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file