diff --git a/CHANGELOG.md b/CHANGELOG.md index dc27243ca..6d113293d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +# [5.20.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.6...v5.20.0-dev.7) (2025-04-15) + + +### Bug Fixes + +* **Spotify:** Fix login by replacing `Spoof signature` patch with new `Spoof package info` patch ([#4794](https://github.com/ReVanced/revanced-patches/issues/4794)) ([d639151](https://github.com/ReVanced/revanced-patches/commit/d639151641352ce651037b17fb65bd58953cd51c)) + +# [5.20.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.5...v5.20.0-dev.6) (2025-04-15) + + +### Bug Fixes + +* **Duolingo - Hide ads:** Support lastest app release ([#4790](https://github.com/ReVanced/revanced-patches/issues/4790)) ([215fccb](https://github.com/ReVanced/revanced-patches/commit/215fccbaf2fdd54251c46cbda106029eb304996b)) + +# [5.20.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.4...v5.20.0-dev.5) (2025-04-14) + + +### Features + +* **YouTube - Swipe controls:** Add option to change volume swipe sensitivity (step size) ([#4557](https://github.com/ReVanced/revanced-patches/issues/4557)) ([8957325](https://github.com/ReVanced/revanced-patches/commit/8957325d78eb42e087c4c1ff0abedb2146aa4423)) + +# [5.20.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.3...v5.20.0-dev.4) (2025-04-14) + + +### Bug Fixes + +* **Spotify - Unlock Spotify Premium:** Remove premium restriction for 'Spotify Connect' ([#4782](https://github.com/ReVanced/revanced-patches/issues/4782)) ([50f5b1a](https://github.com/ReVanced/revanced-patches/commit/50f5b1ac54372542d76e87626f00ddefb54da125)) + +# [5.20.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.2...v5.20.0-dev.3) (2025-04-13) + + +### Bug Fixes + +* **YouTube - Remove background playback restrictions:** Restore PiP button functionality after screen is unlocked ([6837348](https://github.com/ReVanced/revanced-patches/commit/6837348c45156d6743a63fef8b6e045087afbda8)) + +# [5.20.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.1...v5.20.0-dev.2) (2025-04-13) + + +### Features + +* **Spotify - Custom theme:** Add option to use unmodified player background gradient ([#4741](https://github.com/ReVanced/revanced-patches/issues/4741)) ([0ee3693](https://github.com/ReVanced/revanced-patches/commit/0ee36939f43f325afca37119db1cf1af3b63be27)) + +# [5.20.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.1...v5.20.0-dev.1) (2025-04-13) + + +### Features + +* Add `Set target SDK version 34` patch (Disable edge-to-edge display) ([#4780](https://github.com/ReVanced/revanced-patches/issues/4780)) ([dcf6178](https://github.com/ReVanced/revanced-patches/commit/dcf6178f19f86dd1b57d54c855b8c47b086dd33a)) + ## [5.19.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.0...v5.19.1) (2025-04-12) diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index 49dfffaec..9d5907811 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -80,6 +80,9 @@ public final class UnlockPremiumPatch { new OverrideAttribute("streaming-rules", ""), // Enables premium UI in settings and removes the premium button in the nav-bar. new OverrideAttribute("nft-disabled", "1"), + // Enable Spotify Connect and disable other premium related UI, like buying premium. + // It also removes the download button. + new OverrideAttribute("type", "premium"), // Enable Spotify Car Thing hardware device. // Device is discontinued and no longer works with the latest releases, // but it might still work with older app targets. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 75128e3dd..dfc727bda 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -319,6 +319,7 @@ public class Settings extends BaseSettings { parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); public static final IntegerSetting SWIPE_MAGNITUDE_THRESHOLD = new IntegerSetting("revanced_swipe_threshold", 30, true, parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); + public static final IntegerSetting SWIPE_VOLUME_SENSITIVITY = new IntegerSetting("revanced_swipe_volume_sensitivity", 1, true, parent(SWIPE_VOLUME)); public static final BooleanSetting SWIPE_SHOW_CIRCULAR_OVERLAY = new BooleanSetting("revanced_swipe_show_circular_overlay", FALSE, true, parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); public static final BooleanSetting SWIPE_OVERLAY_MINIMAL_STYLE = new BooleanSetting("revanced_swipe_overlay_minimal_style", FALSE, true, diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsConfigurationProvider.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsConfigurationProvider.kt index 08e7e0480..697926244 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsConfigurationProvider.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsConfigurationProvider.kt @@ -1,6 +1,5 @@ package app.revanced.extension.youtube.swipecontrols -import android.content.Context import android.graphics.Color import app.revanced.extension.shared.StringRef.str import app.revanced.extension.shared.Utils @@ -9,12 +8,8 @@ import app.revanced.extension.youtube.shared.PlayerType /** * provider for configuration for volume and brightness swipe controls - * - * @param context the context to create in */ -class SwipeControlsConfigurationProvider( - private val context: Context, -) { +class SwipeControlsConfigurationProvider { //region swipe enable /** * should swipe controls be enabled? (global setting) @@ -60,6 +55,23 @@ class SwipeControlsConfigurationProvider( */ val swipeMagnitudeThreshold: Int get() = Settings.SWIPE_MAGNITUDE_THRESHOLD.get() + + /** + * How much volume will change by single swipe. + * If it is set to 0, it will reset to the default value because 0 would disable swiping. + * */ + val volumeSwipeSensitivity: Int + get() { + val sensitivity = Settings.SWIPE_VOLUME_SENSITIVITY.get() + + if (sensitivity < 1) { + Settings.SWIPE_VOLUME_SENSITIVITY.resetToDefault() + + return Settings.SWIPE_VOLUME_SENSITIVITY.get() + } + + return sensitivity + } //endregion //region overlay adjustments diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt index c889c6d4c..10b70ed95 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt @@ -127,7 +127,7 @@ class SwipeControlsHostActivity : Activity() { private fun initialize() { // create controllers printDebug { "initializing swipe controls controllers" } - config = SwipeControlsConfigurationProvider(this) + config = SwipeControlsConfigurationProvider() keys = VolumeKeysController(this) audio = createAudioController() screen = createScreenController() diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/VolumeKeysController.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/VolumeKeysController.kt index d2b8788df..5d206dfa9 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/VolumeKeysController.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/VolumeKeysController.kt @@ -41,7 +41,7 @@ class VolumeKeysController( private fun handleVolumeKeyEvent(event: KeyEvent, volumeUp: Boolean): Boolean { if (event.action == KeyEvent.ACTION_DOWN) { controller.audio?.apply { - volume += if (volumeUp) 1 else -1 + volume += controller.config.volumeSwipeSensitivity * if (volumeUp) 1 else -1 controller.overlay.onVolumeChanged(volume, maxVolume) } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt index 286a6fe43..a07cf7490 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt @@ -24,6 +24,7 @@ abstract class BaseGestureController( controller.overlay, 10, 1, + controller.config.volumeSwipeSensitivity, ) { /** diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/VolumeAndBrightnessScroller.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/VolumeAndBrightnessScroller.kt index e398696df..ec50aedd7 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/VolumeAndBrightnessScroller.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/VolumeAndBrightnessScroller.kt @@ -41,6 +41,7 @@ interface VolumeAndBrightnessScroller { * @param overlayController overlay controller instance * @param volumeDistance unit distance for volume scrolling, in dp * @param brightnessDistance unit distance for brightness scrolling, in dp + * @param volumeSwipeSensitivity how much volume will change by single swipe */ class VolumeAndBrightnessScrollerImpl( context: Context, @@ -49,6 +50,7 @@ class VolumeAndBrightnessScrollerImpl( private val overlayController: SwipeControlsOverlay, volumeDistance: Int = 10, brightnessDistance: Int = 1, + private val volumeSwipeSensitivity: Int, ) : VolumeAndBrightnessScroller { // region volume @@ -60,7 +62,7 @@ class VolumeAndBrightnessScrollerImpl( ), ) { _, _, direction -> volumeController?.run { - volume += direction + volume += direction * volumeSwipeSensitivity overlayController.onVolumeChanged(volume, maxVolume) } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt index 2874303f7..8df6aeeee 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt @@ -25,7 +25,7 @@ class SwipeControlsOverlayLayout( private val config: SwipeControlsConfigurationProvider, ) : RelativeLayout(context), SwipeControlsOverlay { - constructor(context: Context) : this(context, SwipeControlsConfigurationProvider(context)) + constructor(context: Context) : this(context, SwipeControlsConfigurationProvider()) // Drawable icons for brightness and volume private val autoBrightnessIcon: Drawable = getDrawable("revanced_ic_sc_brightness_auto") diff --git a/gradle.properties b/gradle.properties index 42b4a5f9f..4ad5f540b 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.19.1 +version = 5.20.0-dev.7 diff --git a/patches/api/patches.api b/patches/api/patches.api index 5416c799e..711eccede 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -108,6 +108,10 @@ public final class app/revanced/patches/all/misc/shortcut/sharetargets/RemoveSha public static final fun getRemoveShareTargetsPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } +public final class app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34Kt { + public static final fun getSetTargetSdkVersion34 ()Lapp/revanced/patcher/patch/ResourcePatch; +} + public abstract interface class app/revanced/patches/all/misc/transformation/IMethodCall { public abstract fun getDefinedClassName ()Ljava/lang/String; public abstract fun getMethodName ()Ljava/lang/String; @@ -838,6 +842,10 @@ public final class app/revanced/patches/spotify/misc/extension/ExtensionPatchKt public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatchKt { + public static final fun getSpoofPackageInfoPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/spotify/misc/fix/SpoofSignaturePatchKt { public static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1521,7 +1529,11 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat } public final class app/revanced/util/BytecodeUtilsKt { + public static final fun addInstructionsAtControlFlowLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V + public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;D)Z + public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;F)Z public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z + public static final fun findFreeRegister (Lcom/android/tools/smali/dexlib2/iface/Method;I[I)I public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List; public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List; public static final fun findInstructionIndicesReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List; @@ -1548,9 +1560,17 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I + public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;D)I + public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;F)I public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)I + public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;D)I + public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;F)I public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I + public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;D)I + public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;F)I public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;J)I + public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;D)I + public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;F)I public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I public static final fun indexOfFirstResourceId (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I public static final fun indexOfFirstResourceIdOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34.kt new file mode 100644 index 000000000..c79654d1f --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.all.misc.targetSdk + +import app.revanced.patcher.patch.resourcePatch +import app.revanced.util.getNode +import org.w3c.dom.Element +import java.util.logging.Logger + +@Suppress("unused") +val setTargetSdkVersion34 = resourcePatch( + name = "Set target SDK version 34", + description = "Changes the target SDK to version 34 (Android 14). " + + "For devices running Android 15+, this will disable edge-to-edge display.", + use = false, +) { + execute { + val targetSdkOverride = 34 // Android 14. + + document("AndroidManifest.xml").use { document -> + fun getLogger() = Logger.getLogger(this::class.java.name) + + // Ideally, the override should only be applied if the existing target is higher. + // But since ApkTool does not add targetSdkVersion to the decompiled AndroidManifest, + // there is no way to check targetSdkVersion. Instead, check compileSdkVersion and print a warning. + try { + val manifestElement = document.getNode("manifest") as Element + val compileSdkVersion = Integer.parseInt( + manifestElement.getAttribute("android:compileSdkVersion") + ) + if (compileSdkVersion <= targetSdkOverride) { + getLogger().warning( + "This app does not appear to use a target SDK above $targetSdkOverride: " + + "(compileSdkVersion: $compileSdkVersion)" + ) + } + } catch (_: Exception) { + getLogger().warning("Could not check compileSdkVersion") + } + + // Change targetSdkVersion to override value. + document.getElementsByTagName("manifest").item(0).let { + var element = it.ownerDocument.createElement("uses-sdk") + element.setAttribute("android:targetSdkVersion", targetSdkOverride.toString()) + + it.appendChild(element) + } + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt index 59b0644d9..9a23af8c8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt @@ -12,7 +12,8 @@ internal val initializeMonetizationDebugSettingsFingerprint = fingerprint { "Z", // useDebugBilling "Z", // showManageSubscriptions "Z", // alwaysShowSuperAds - "Lcom/duolingo/debug/FamilyQuestOverride;", + // matches "Lcom/duolingo/debug/FamilyQuestOverride;" or "Lcom/duolingo/data/debug/monetization/FamilyQuestOverride;" + "Lcom/duolingo/", ) opcodes(Opcode.IPUT_BOOLEAN) } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index 7872b00be..78deda394 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -14,7 +14,7 @@ import app.revanced.util.findFreeRegister import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.insertFeatureFlagBooleanOverride +import app.revanced.util.insertLiteralOverride import app.revanced.util.returnEarly import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -235,7 +235,7 @@ fun spoofVideoStreamsPatch( // region Fix iOS livestream current time. - hlsCurrentTimeFingerprint.method.insertFeatureFlagBooleanOverride( + hlsCurrentTimeFingerprint.method.insertLiteralOverride( HLS_CURRENT_TIME_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z" ) @@ -245,21 +245,21 @@ fun spoofVideoStreamsPatch( // region turn off stream config replacement feature flag. if (fixMediaFetchHotConfigChanges()) { - mediaFetchHotConfigFingerprint.method.insertFeatureFlagBooleanOverride( + mediaFetchHotConfigFingerprint.method.insertLiteralOverride( MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" ) } if (fixMediaFetchHotConfigAlternativeChanges()) { - mediaFetchHotConfigAlternativeFingerprint.method.insertFeatureFlagBooleanOverride( + mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride( MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" ) } if (fixParsePlaybackResponseFeatureFlag()) { - playbackStartDescriptorFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride( + playbackStartDescriptorFeatureFlagFingerprint.method.insertLiteralOverride( PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z" ) 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 deleted file mode 100644 index 2f639ef8d..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt +++ /dev/null @@ -1,82 +0,0 @@ -package app.revanced.patches.spotify.layout.theme - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -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 -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference - -private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/layout/theme/CustomThemePatch;" - -internal val customThemeByteCodePatch = bytecodePatch { - dependsOn(sharedExtensionPatch) - - val backgroundColor by spotifyBackgroundColor - 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 - - addInstructions( - index + 1, - """ - const-string v$register, "$colorString" - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getThemeColor(Ljava/lang/String;)J - move-result-wide v$register - """ - ) - } - - val encoreColorsClassName = with(encoreThemeFingerprint) { - // Find index of the first static get found after the string constant. - val encoreColorsFieldReferenceIndex = originalMethod.indexOfFirstInstructionOrThrow( - stringMatches!!.first().index, - Opcode.SGET_OBJECT - ) - - originalMethod.getInstruction(encoreColorsFieldReferenceIndex) - .getReference()!!.definingClass - } - - val encoreColorsConstructorFingerprint = fingerprint { - accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) - custom { method, classDef -> - classDef.type == encoreColorsClassName && - method.containsLiteralInstruction(PLAYLIST_BACKGROUND_COLOR_LITERAL) - } - } - - encoreColorsConstructorFingerprint.method.apply { - // Playlist song list background color. - addColorChangeInstructions(PLAYLIST_BACKGROUND_COLOR_LITERAL, backgroundColor!!) - - // Share menu background color. - addColorChangeInstructions(SHARE_MENU_BACKGROUND_COLOR_LITERAL, backgroundColorSecondary!!) - } - - homeCategoryPillColorsFingerprint.method.apply { - // Home category pills background color. - addColorChangeInstructions(HOME_CATEGORY_PILL_COLOR_LITERAL, backgroundColorSecondary!!) - } - - settingsHeaderColorFingerprint.method.apply { - // Settings header background color. - addColorChangeInstructions(SETTINGS_HEADER_COLOR_LITERAL, backgroundColorSecondary!!) - } - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt index 5f2f09435..da0d8482d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt @@ -1,8 +1,133 @@ package app.revanced.patches.spotify.layout.theme +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fingerprint +import app.revanced.patcher.patch.booleanOption +import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch +import app.revanced.patcher.patch.stringOption +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 +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference import org.w3c.dom.Element +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/layout/theme/CustomThemePatch;" + +internal val spotifyBackgroundColor = stringOption( + key = "backgroundColor", + default = "@android:color/black", + title = "Primary background color", + description = "The background color. Can be a hex color or a resource reference.", + required = true, +) + +internal val overridePlayerGradientColor = booleanOption( + key = "overridePlayerGradientColor", + default = false, + title = "Override player gradient color", + description = "Apply primary background color to the player gradient color, which changes dynamically with the song.", + required = false +) + +internal val spotifyBackgroundColorSecondary = stringOption( + key = "backgroundColorSecondary", + default = "#FF121212", + title = "Secondary background color", + description = + "The secondary background color. (e.g. playlist list in home, player artist, song credits). Can be a hex color or a resource reference.", + required = true, +) + +internal val spotifyAccentColor = stringOption( + key = "accentColor", + default = "#FF1ED760", + title = "Accent color", + description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.", + required = true, +) + +internal val spotifyAccentColorPressed = stringOption( + key = "accentColorPressed", + default = "#FF169C46", + title = "Pressed dark theme accent color", + description = + "The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.", + required = true, +) + +private val customThemeBytecodePatch = bytecodePatch { + dependsOn(sharedExtensionPatch) + + 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 + + addInstructions( + index + 1, + """ + const-string v$register, "$colorString" + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getThemeColor(Ljava/lang/String;)J + move-result-wide v$register + """ + ) + } + + val encoreColorsClassName = with(encoreThemeFingerprint.originalMethod) { + // "Encore" colors are referenced right before the value of POSITIVE_INFINITY is returned. + // Begin the instruction find using the index of where POSITIVE_INFINITY is set into the register. + val positiveInfinityIndex = indexOfFirstLiteralInstructionOrThrow( + Float.POSITIVE_INFINITY + ) + val encoreColorsFieldReferenceIndex = indexOfFirstInstructionReversedOrThrow( + positiveInfinityIndex, + Opcode.SGET_OBJECT + ) + + getInstruction(encoreColorsFieldReferenceIndex) + .getReference()!!.definingClass + } + + val encoreColorsConstructorFingerprint = fingerprint { + accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) + custom { method, classDef -> + classDef.type == encoreColorsClassName && + method.containsLiteralInstruction(PLAYLIST_BACKGROUND_COLOR_LITERAL) + } + } + + val backgroundColor by spotifyBackgroundColor + val backgroundColorSecondary by spotifyBackgroundColorSecondary + + encoreColorsConstructorFingerprint.method.apply { + addColorChangeInstructions(PLAYLIST_BACKGROUND_COLOR_LITERAL, backgroundColor!!) + addColorChangeInstructions(SHARE_MENU_BACKGROUND_COLOR_LITERAL, backgroundColorSecondary!!) + } + + homeCategoryPillColorsFingerprint.method.addColorChangeInstructions( + HOME_CATEGORY_PILL_COLOR_LITERAL, + backgroundColorSecondary!! + ) + + settingsHeaderColorFingerprint.method.addColorChangeInstructions( + SETTINGS_HEADER_COLOR_LITERAL, + backgroundColorSecondary!! + ) + } +} + @Suppress("unused") val customThemePatch = resourcePatch( name = "Custom theme", @@ -11,9 +136,10 @@ val customThemePatch = resourcePatch( ) { compatibleWith("com.spotify.music") - dependsOn(customThemeByteCodePatch) + dependsOn(customThemeBytecodePatch) val backgroundColor by spotifyBackgroundColor() + val overridePlayerGradientColor by overridePlayerGradientColor() val backgroundColorSecondary by spotifyBackgroundColorSecondary() val accentColor by spotifyAccentColor() val accentColorPressed by spotifyAccentColorPressed() @@ -25,31 +151,39 @@ val customThemePatch = resourcePatch( val childNodes = resourcesNode.childNodes for (i in 0 until childNodes.length) { val node = childNodes.item(i) as? Element ?: continue + val name = node.getAttribute("name") - node.textContent = when (node.getAttribute("name")) { - // Gradient next to user photo and "All" in home page + // Skip overriding song/player gradient start color if the option is disabled. + // Gradient end color should be themed regardless to allow the gradient to connect with + // our primary background color. + if (name == "bg_gradient_start_color" && !overridePlayerGradientColor!!) { + continue + } + + node.textContent = when (name) { + // Gradient next to user photo and "All" in home page. "dark_base_background_base", - // Main background + // Main background. "gray_7", - // Left sidebar background in tablet mode + // Left sidebar background in tablet mode. "gray_10", - // Add account, Settings and privacy, View Profile left sidebar background + // "Add account", "Settings and privacy", "View Profile" left sidebar background. "dark_base_background_elevated_base", - // Song/player background + // Song/player gradient start/end color. "bg_gradient_start_color", "bg_gradient_end_color", - // Login screen - "sthlm_blk", "sthlm_blk_grad_start", "stockholm_black", - // Misc + // Login screen background and gradient start. + "sthlm_blk", "sthlm_blk_grad_start", + // Misc. "image_placeholder_color", -> backgroundColor - // Track credits, merch in song player + // Track credits, merch background in song player. "track_credits_card_bg", "benefit_list_default_color", "merch_card_background", - // Playlist list background in home page + // Playlist list background in home page. "opacity_white_10", - // About artist background in song player + // "About the artist" background in song player. "gray_15", - // What's New pills background + // "What's New" pills background. "dark_base_background_tinted_highlight" -> backgroundColorSecondary @@ -59,5 +193,13 @@ val customThemePatch = resourcePatch( } } } + + // Login screen gradient. + document("res/drawable/start_screen_gradient.xml").use { document -> + val gradientNode = document.getElementsByTagName("gradient").item(0) as Element + + gradientNode.setAttribute("android:startColor", backgroundColor) + gradientNode.setAttribute("android:endColor", backgroundColor) + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt index 28943e040..ce4840283 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt @@ -5,13 +5,13 @@ import app.revanced.util.containsLiteralInstruction import com.android.tools.smali.dexlib2.AccessFlags internal val encoreThemeFingerprint = fingerprint { - strings("Encore theme was not provided.") // Partial string match. + strings("No EncoreLayoutTheme provided") } -internal const val SETTINGS_HEADER_COLOR_LITERAL = 0xFF282828 -internal const val HOME_CATEGORY_PILL_COLOR_LITERAL = 0xFF333333 internal const val PLAYLIST_BACKGROUND_COLOR_LITERAL = 0xFF121212 internal const val SHARE_MENU_BACKGROUND_COLOR_LITERAL = 0xFF1F1F1F +internal const val HOME_CATEGORY_PILL_COLOR_LITERAL = 0xFF333333 +internal const val SETTINGS_HEADER_COLOR_LITERAL = 0xFF282828 internal val homeCategoryPillColorsFingerprint = fingerprint{ accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Options.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Options.kt deleted file mode 100644 index e71c97912..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Options.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.spotify.layout.theme - -import app.revanced.patcher.patch.stringOption - -internal val spotifyBackgroundColor = stringOption( - key = "backgroundColor", - default = "@android:color/black", - title = "Primary background color", - description = "The background color. Can be a hex color or a resource reference.", - required = true, -) - -internal val spotifyBackgroundColorSecondary = stringOption( - key = "backgroundColorSecondary", - default = "#FF121212", - title = "Secondary background color", - description = "The secondary background color. (e.g. playlist list, player arist, credits). Can be a hex color or a resource reference.", - required = true, -) - -internal val spotifyAccentColor = stringOption( - key = "accentColor", - default = "#FF1ED760", - title = "Accent color", - description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.", - required = true, -) - -internal val spotifyAccentColorPressed = stringOption( - key = "accentColorPressed", - default = "#FF169C46", - title = "Pressed dark theme accent color", - description = - "The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.", - required = true, -) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index 57d95e1e7..8678517f9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -49,7 +49,7 @@ val unlockPremiumPatch = bytecodePatch( } // Override the attributes map in the getter method. - with(productStateProtoFingerprint.method) { + productStateProtoFingerprint.method.apply { val getAttributesMapIndex = indexOfFirstInstructionOrThrow(Opcode.IGET_OBJECT) val attributesMapRegister = getInstruction(getAttributesMapIndex).registerA @@ -62,10 +62,11 @@ val unlockPremiumPatch = bytecodePatch( // Add the query parameter trackRows to show popular tracks in the artist page. - with(buildQueryParametersFingerprint) { + buildQueryParametersFingerprint.apply { val addQueryParameterConditionIndex = method.indexOfFirstInstructionReversedOrThrow( stringMatches!!.first().index, Opcode.IF_EQZ ) + method.replaceInstruction(addQueryParameterConditionIndex, "nop") } @@ -114,17 +115,19 @@ val unlockPremiumPatch = bytecodePatch( // Disable the "Spotify Premium" upsell experiment in context menus. - with(contextMenuExperimentsFingerprint) { + contextMenuExperimentsFingerprint.apply { val moveIsEnabledIndex = method.indexOfFirstInstructionOrThrow( stringMatches!!.first().index, Opcode.MOVE_RESULT ) val isUpsellEnabledRegister = method.getInstruction(moveIsEnabledIndex).registerA + method.replaceInstruction(moveIsEnabledIndex, "const/4 v$isUpsellEnabledRegister, 0") } // Make featureTypeCase_ accessible so we can check the home section type in the extension. homeSectionFingerprint.classDef.fields.first { it.name == "featureTypeCase_" }.apply { + // Add public flag and remove private. accessFlags = accessFlags.or(AccessFlags.PUBLIC.value).and(AccessFlags.PRIVATE.value.inv()) } @@ -143,7 +146,7 @@ val unlockPremiumPatch = bytecodePatch( // Protobuffer list has an 'isMutable' boolean parameter that sets the mutability. // Forcing that always on breaks unrelated code in strange ways. // Instead, remove the method call that checks if the list is unmodifiable. - with(protobufListRemoveFingerprint.method) { + protobufListRemoveFingerprint.method.apply { val invokeThrowUnmodifiableIndex = indexOfFirstInstructionOrThrow { val reference = getReference() opcode == Opcode.INVOKE_VIRTUAL && @@ -155,7 +158,7 @@ val unlockPremiumPatch = bytecodePatch( } // Remove ads sections from home. - with(homeStructureFingerprint.method) { + homeStructureFingerprint.method.apply { val getSectionsIndex = indexOfFirstInstructionOrThrow(Opcode.IGET_OBJECT) val sectionsRegister = getInstruction(getSectionsIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt index c6e476c56..f8959ae64 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt @@ -2,4 +2,16 @@ package app.revanced.patches.spotify.misc.fix import app.revanced.patcher.fingerprint -internal val getAppSignatureFingerprint = fingerprint { strings("Failed to get the application signatures") } +internal val getPackageInfoFingerprint = fingerprint { + strings( + "Failed to get the application signatures", + "Failed to get installer package" + ) +} + +internal val getPackageInfoLegacyFingerprint = fingerprint { + strings( + "Failed to get the application signatures" + ) +} + diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt new file mode 100644 index 000000000..c06f2a04c --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt @@ -0,0 +1,72 @@ +package app.revanced.patches.spotify.misc.fix + +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET +import app.revanced.util.addInstructionsAtControlFlowLabel +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction + +@Suppress("unused") +val spoofPackageInfoPatch = bytecodePatch( + name = "Spoof package info", + description = "Spoofs the package info of the app to fix various functions of the app.", +) { + compatibleWith("com.spotify.music") + + execute { + val getPackageInfoFingerprint = if (IS_SPOTIFY_LEGACY_APP_TARGET) { + getPackageInfoLegacyFingerprint + } else { + getPackageInfoFingerprint + } + + getPackageInfoFingerprint.method.apply { + val stringMatches = getPackageInfoFingerprint.stringMatches!! + + // region Spoof signature. + + val failedToGetSignaturesStringIndex = stringMatches.first().index + + val concatSignaturesIndex = indexOfFirstInstructionReversedOrThrow( + failedToGetSignaturesStringIndex, + Opcode.MOVE_RESULT_OBJECT, + ) + + val signatureRegister = getInstruction(concatSignaturesIndex).registerA + val expectedSignature = "d6a6dced4a85f24204bf9505ccc1fce114cadb32" + + replaceInstruction(concatSignaturesIndex, "const-string v$signatureRegister, \"$expectedSignature\"") + + // endregion + + // region Spoof installer name. + + if (IS_SPOTIFY_LEGACY_APP_TARGET) { + // Installer name is not used in the legacy app target. + return@execute + } + + val expectedInstallerName = "com.android.vending" + + val returnInstallerNameIndex = indexOfFirstInstructionOrThrow( + stringMatches.last().index, + Opcode.RETURN_OBJECT + ) + + val installerNameRegister = getInstruction( + returnInstallerNameIndex + ).registerA + + addInstructionsAtControlFlowLabel( + returnInstallerNameIndex, + "const-string v$installerNameRegister, \"$expectedInstallerName\"" + ) + + // endregion + } + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt index 6dfd31e45..7ac278ff3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt @@ -1,33 +1,13 @@ package app.revanced.patches.spotify.misc.fix -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.indexOfFirstInstructionReversedOrThrow -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +@Deprecated("Superseded by spoofPackageInfoPatch", ReplaceWith("spoofPackageInfoPatch")) @Suppress("unused") val spoofSignaturePatch = bytecodePatch( - name = "Spoof signature", - description = "Spoofs the signature of the app to fix various functions of the app.", + description = "Spoofs the signature of the app fix various functions of the app.", ) { compatibleWith("com.spotify.music") - execute { - getAppSignatureFingerprint.method.apply { - val failedToGetSignaturesStringMatch = getAppSignatureFingerprint.stringMatches!!.first() - - val concatSignaturesIndex = indexOfFirstInstructionReversedOrThrow( - failedToGetSignaturesStringMatch.index, - Opcode.MOVE_RESULT_OBJECT, - ) - - val register = getInstruction(concatSignaturesIndex).registerA - - val expectedSignature = "d6a6dced4a85f24204bf9505ccc1fce114cadb32" - - replaceInstruction(concatSignaturesIndex, "const-string v$register, \"$expectedSignature\"") - } - } + dependsOn(spoofPackageInfoPatch) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt index f385f3543..d20ebf9a7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt @@ -47,6 +47,7 @@ private val swipeControlsResourcePatch = resourcePatch { TextPreference("revanced_swipe_overlay_background_opacity", inputType = InputType.NUMBER), TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER), TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER), + TextPreference("revanced_swipe_volume_sensitivity", inputType = InputType.NUMBER), ) copyResources( @@ -117,7 +118,7 @@ val swipeControlsPatch = bytecodePatch( // region patch to enable/disable swipe to change video. if (is_19_43_or_greater) { - swipeChangeVideoFingerprint.method.insertFeatureFlagBooleanOverride( + swipeChangeVideoFingerprint.method.insertLiteralOverride( SWIPE_CHANGE_VIDEO_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z" ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt index 20b557807..3feee5b30 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt @@ -18,7 +18,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.insertFeatureFlagBooleanOverride +import app.revanced.util.insertLiteralOverride 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.reference.MethodReference @@ -119,17 +119,17 @@ val navigationButtonsPatch = bytecodePatch( // Force on/off translucent effect on status bar and navigation buttons. if (is_19_25_or_greater) { - translucentNavigationStatusBarFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride( + translucentNavigationStatusBarFeatureFlagFingerprint.method.insertLiteralOverride( TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationStatusBar(Z)Z", ) - translucentNavigationButtonsFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride( + translucentNavigationButtonsFeatureFlagFingerprint.method.insertLiteralOverride( TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", ) - translucentNavigationButtonsSystemFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride( + translucentNavigationButtonsSystemFeatureFlagFingerprint.method.insertLiteralOverride( TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt index 87ef9b707..98640db4e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt @@ -278,7 +278,7 @@ val miniplayerPatch = bytecodePatch( fun Fingerprint.insertMiniplayerFeatureFlagBooleanOverride( literal: Long, extensionMethod: String, - ) = method.insertFeatureFlagBooleanOverride( + ) = method.insertLiteralOverride( literal, "$EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(Z)Z" ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt index 24896be99..76086c0e4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt @@ -5,7 +5,7 @@ import app.revanced.patches.youtube.layout.shortsplayer.openShortsInRegularPlaye import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch -import app.revanced.util.insertFeatureFlagBooleanOverride +import app.revanced.util.insertLiteralOverride internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch;" @@ -24,7 +24,7 @@ internal val openVideosFullscreenHookPatch = bytecodePatch { return@execute } - openVideosFullscreenPortraitFingerprint.method.insertFeatureFlagBooleanOverride( + openVideosFullscreenPortraitFingerprint.method.insertLiteralOverride( OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->openVideoFullscreenPortrait(Z)Z" ) 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 2185ef849..76fe99b31 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 @@ -28,9 +28,8 @@ 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 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 @@ -229,16 +228,9 @@ val seekbarColorPatch = bytecodePatch( execute { fun MutableMethod.addColorChangeInstructions(resourceId: Long) { - val index = indexOfFirstLiteralInstructionOrThrow(resourceId) - val insertIndex = indexOfFirstInstructionOrThrow(index, Opcode.MOVE_RESULT) - val register = getInstruction(insertIndex).registerA - - addInstructions( - insertIndex + 1, - """ - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I - move-result v$register - """ + insertLiteralOverride( + resourceId, + "$EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I" ) } @@ -354,7 +346,7 @@ val seekbarColorPatch = bytecodePatch( launchScreenLayoutTypeFingerprint, mainActivityOnCreateFingerprint ).forEach { fingerprint -> - fingerprint.method.insertFeatureFlagBooleanOverride( + fingerprint.method.insertLiteralOverride( launchScreenLayoutTypeLotteFeatureFlag, "$EXTENSION_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z" ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt index 77bba81ed..da0f29fc8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt @@ -21,7 +21,7 @@ import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.forEachChildElement -import app.revanced.util.insertFeatureFlagBooleanOverride +import app.revanced.util.insertLiteralOverride import org.w3c.dom.Element private const val EXTENSION_CLASS_DESCRIPTOR = @@ -233,7 +233,7 @@ val themePatch = bytecodePatch( SwitchPreference("revanced_gradient_loading_screen"), ) - useGradientLoadingScreenFingerprint.method.insertFeatureFlagBooleanOverride( + useGradientLoadingScreenFingerprint.method.insertLiteralOverride( GRADIENT_LOADING_SCREEN_AB_CONSTANT, "$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z" ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index 646a47a7d..4826dc78b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -12,6 +12,8 @@ import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch +import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.video.information.videoInformationPatch @@ -44,6 +46,7 @@ val backgroundPlaybackPatch = bytecodePatch( playerTypeHookPatch, videoInformationPatch, settingsPatch, + versionCheckPatch ) compatibleWith( @@ -100,5 +103,13 @@ val backgroundPlaybackPatch = bytecodePatch( // Force allowing background play for videos labeled for kids. kidsBackgroundPlaybackPolicyControllerFingerprint.method.returnEarly() + + // Fix PiP buttons not working after locking/unlocking device screen. + if (is_19_34_or_greater) { + pipInputConsumerFeatureFlagFingerprint.method.insertLiteralOverride( + PIP_INPUT_CONSUMER_FEATURE_FLAG, + false + ) + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt index b12c8157c..a5c077115 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt @@ -83,4 +83,11 @@ internal val shortsBackgroundPlaybackFeatureFlagFingerprint = fingerprint { returns("Z") parameters() literal { 45415425 } +} + +internal const val PIP_INPUT_CONSUMER_FEATURE_FLAG = 45638483L + +// Fix 'E/InputDispatcher: Window handle pip_input_consumer has no registered input channel' +internal val pipInputConsumerFeatureFlagFingerprint = fingerprint { + literal { PIP_INPUT_CONSUMER_FEATURE_FLAG} } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt index 8ef699f6b..ec7d89363 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt @@ -269,7 +269,7 @@ val settingsPatch = bytecodePatch( } // Add setting to force cairo settings fragment on/off. - cairoFragmentConfigFingerprint.method.insertFeatureFlagBooleanOverride( + cairoFragmentConfigFingerprint.method.insertLiteralOverride( CAIRO_CONFIG_LITERAL_VALUE, "$activityHookClassDescriptor->useCairoSettingsFragment(Z)Z" ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt index 53151489b..d6a7fb561 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt @@ -121,11 +121,11 @@ internal val customPlaybackSpeedPatch = bytecodePatch( // Override the min/max speeds that can be used. speedLimiterFingerprint.method.apply { - val limitMinIndex = indexOfFirstLiteralInstructionOrThrow(0.25f.toRawBits().toLong()) - var limitMaxIndex = indexOfFirstLiteralInstruction(2.0f.toRawBits().toLong()) + val limitMinIndex = indexOfFirstLiteralInstructionOrThrow(0.25f) + var limitMaxIndex = indexOfFirstLiteralInstruction(2.0f) // Newer targets have 4x max speed. if (limitMaxIndex < 0) { - limitMaxIndex = indexOfFirstLiteralInstructionOrThrow(4.0f.toRawBits().toLong()) + limitMaxIndex = indexOfFirstLiteralInstructionOrThrow(4.0f) } val limitMinRegister = getInstruction(limitMinIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index 4d3826865..b0bd29fd7 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -14,6 +14,9 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappings +import app.revanced.util.InstructionUtils.Companion.branchOpcodes +import app.revanced.util.InstructionUtils.Companion.returnOpcodes +import app.revanced.util.InstructionUtils.Companion.writeOpcodes import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode.* import com.android.tools.smali.dexlib2.iface.Method @@ -43,7 +46,7 @@ import java.util.EnumSet * @throws IllegalArgumentException If a branch or conditional statement is encountered * before a suitable register is found. */ -internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): Int { +fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): Int { if (implementation == null) { throw IllegalArgumentException("Method has no implementation: $this") } @@ -51,82 +54,6 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: throw IllegalArgumentException("startIndex out of bounds: $startIndex") } - // All registers used by an instruction. - fun Instruction.getRegistersUsed() = when (this) { - is FiveRegisterInstruction -> { - when (registerCount) { - 1 -> listOf(registerC) - 2 -> listOf(registerC, registerD) - 3 -> listOf(registerC, registerD, registerE) - 4 -> listOf(registerC, registerD, registerE, registerF) - else -> listOf(registerC, registerD, registerE, registerF, registerG) - } - } - is ThreeRegisterInstruction -> listOf(registerA, registerB, registerC) - is TwoRegisterInstruction -> listOf(registerA, registerB) - is OneRegisterInstruction -> listOf(registerA) - is RegisterRangeInstruction -> (startRegister until (startRegister + registerCount)).toList() - else -> emptyList() - } - - // Register that is written to by an instruction. - fun Instruction.getWriteRegister() : Int { - // Two and three register instructions extend OneRegisterInstruction. - if (this is OneRegisterInstruction) return registerA - throw IllegalStateException("Not a write instruction: $this") - } - - val writeOpcodes = EnumSet.of( - ARRAY_LENGTH, - INSTANCE_OF, - NEW_INSTANCE, NEW_ARRAY, - MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, - MOVE_OBJECT_FROM16, MOVE_OBJECT_16, MOVE_RESULT, MOVE_RESULT_WIDE, MOVE_RESULT_OBJECT, MOVE_EXCEPTION, - CONST, CONST_4, CONST_16, CONST_HIGH16, CONST_WIDE_16, CONST_WIDE_32, - CONST_WIDE, CONST_WIDE_HIGH16, CONST_STRING, CONST_STRING_JUMBO, - IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, IGET_BYTE, IGET_CHAR, IGET_SHORT, - IGET_VOLATILE, IGET_WIDE_VOLATILE, IGET_OBJECT_VOLATILE, - SGET, SGET_WIDE, SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, SGET_CHAR, SGET_SHORT, - SGET_VOLATILE, SGET_WIDE_VOLATILE, SGET_OBJECT_VOLATILE, - AGET, AGET_WIDE, AGET_OBJECT, AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT, - // Arithmetic and logical operations. - ADD_DOUBLE_2ADDR, ADD_DOUBLE, ADD_FLOAT_2ADDR, ADD_FLOAT, ADD_INT_2ADDR, - ADD_INT_LIT8, ADD_INT, ADD_LONG_2ADDR, ADD_LONG, ADD_INT_LIT16, - AND_INT_2ADDR, AND_INT_LIT8, AND_INT_LIT16, AND_INT, AND_LONG_2ADDR, AND_LONG, - DIV_DOUBLE_2ADDR, DIV_DOUBLE, DIV_FLOAT_2ADDR, DIV_FLOAT, DIV_INT_2ADDR, - DIV_INT_LIT16, DIV_INT_LIT8, DIV_INT, DIV_LONG_2ADDR, DIV_LONG, - DOUBLE_TO_FLOAT, DOUBLE_TO_INT, DOUBLE_TO_LONG, - FLOAT_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, - INT_TO_BYTE, INT_TO_CHAR, INT_TO_DOUBLE, INT_TO_FLOAT, INT_TO_LONG, INT_TO_SHORT, - LONG_TO_DOUBLE, LONG_TO_FLOAT, LONG_TO_INT, - MUL_DOUBLE_2ADDR, MUL_DOUBLE, MUL_FLOAT_2ADDR, MUL_FLOAT, MUL_INT_2ADDR, - MUL_INT_LIT16, MUL_INT_LIT8, MUL_INT, MUL_LONG_2ADDR, MUL_LONG, - NEG_DOUBLE, NEG_FLOAT, NEG_INT, NEG_LONG, - NOT_INT, NOT_LONG, - OR_INT_2ADDR, OR_INT_LIT16, OR_INT_LIT8, OR_INT, OR_LONG_2ADDR, OR_LONG, - REM_DOUBLE_2ADDR, REM_DOUBLE, REM_FLOAT_2ADDR, REM_FLOAT, REM_INT_2ADDR, - REM_INT_LIT16, REM_INT_LIT8, REM_INT, REM_LONG_2ADDR, REM_LONG, - RSUB_INT_LIT8, RSUB_INT, - SHL_INT_2ADDR, SHL_INT_LIT8, SHL_INT, SHL_LONG_2ADDR, SHL_LONG, - SHR_INT_2ADDR, SHR_INT_LIT8, SHR_INT, SHR_LONG_2ADDR, SHR_LONG, - SUB_DOUBLE_2ADDR, SUB_DOUBLE, SUB_FLOAT_2ADDR, SUB_FLOAT, SUB_INT_2ADDR, - SUB_INT, SUB_LONG_2ADDR, SUB_LONG, - USHR_INT_2ADDR, USHR_INT_LIT8, USHR_INT, USHR_LONG_2ADDR, USHR_LONG, - XOR_INT_2ADDR, XOR_INT_LIT16, XOR_INT_LIT8, XOR_INT, XOR_LONG_2ADDR, XOR_LONG, - ) - - val branchOpcodes = EnumSet.of( - GOTO, GOTO_16, GOTO_32, - IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE, - IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ, - PACKED_SWITCH_PAYLOAD, SPARSE_SWITCH_PAYLOAD - ) - - val returnOpcodes = EnumSet.of( - RETURN_VOID, RETURN, RETURN_WIDE, RETURN_OBJECT, RETURN_VOID_NO_BARRIER, - THROW - ) - // Highest 4-bit register available, exclusive. Ideally return a free register less than this. val maxRegister4Bits = 16 var bestFreeRegisterFound: Int? = null @@ -134,10 +61,9 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: for (i in startIndex until instructions.count()) { val instruction = getInstruction(i) - val instructionRegisters = instruction.getRegistersUsed() + val instructionRegisters = instruction.registersUsed - if (instruction.opcode in returnOpcodes) { - // Method returns. + if (instruction.isReturnInstruction) { usedRegisters.addAll(instructionRegisters) // Use lowest register that hasn't been encountered. @@ -157,7 +83,7 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: "$startIndex excluding: $registersToExclude") } - if (instruction.opcode in branchOpcodes) { + if (instruction.isBranchInstruction) { if (bestFreeRegisterFound != null) { return bestFreeRegisterFound } @@ -165,9 +91,9 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: throw IllegalArgumentException("Encountered a branch statement before a free register could be found") } - if (instruction.opcode in writeOpcodes) { - val writeRegister = instruction.getWriteRegister() + val writeRegister = instruction.writeRegister + if (writeRegister != null) { if (writeRegister !in usedRegisters) { // Verify the register is only used for write and not also as a parameter. // If the instruction uses the write register once then it's not also a read register. @@ -194,6 +120,53 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: throw IllegalArgumentException("Start index is outside the range of normal control flow: $startIndex") } +/** + * @return The registers used by this instruction. + */ +internal val Instruction.registersUsed: List + get() = when (this) { + is FiveRegisterInstruction -> { + when (registerCount) { + 1 -> listOf(registerC) + 2 -> listOf(registerC, registerD) + 3 -> listOf(registerC, registerD, registerE) + 4 -> listOf(registerC, registerD, registerE, registerF) + else -> listOf(registerC, registerD, registerE, registerF, registerG) + } + } + is ThreeRegisterInstruction -> listOf(registerA, registerB, registerC) + is TwoRegisterInstruction -> listOf(registerA, registerB) + is OneRegisterInstruction -> listOf(registerA) + is RegisterRangeInstruction -> (startRegister until (startRegister + registerCount)).toList() + else -> emptyList() + } + +/** + * @return The register that is written to by this instruction, + * or NULL if this is not a write opcode. + */ +internal val Instruction.writeRegister: Int? + get() { + if (this.opcode !in writeOpcodes) { + return null + } + if (this !is OneRegisterInstruction) { + throw IllegalStateException("Not a write instruction: $this") + } + return registerA + } + +/** + * @return If this instruction is an unconditional or conditional branch opcode. + */ +internal val Instruction.isBranchInstruction: Boolean + get() = this.opcode in branchOpcodes + +/** + * @return If this instruction returns or throws. + */ +internal val Instruction.isReturnInstruction: Boolean + get() = this.opcode in returnOpcodes /** * Find the [MutableMethod] from a given [Method] in a [MutableClass]. @@ -247,7 +220,7 @@ fun MutableMethod.injectHideViewCall( * (patch code) * (original code) */ -internal fun MutableMethod.addInstructionsAtControlFlowLabel( +fun MutableMethod.addInstructionsAtControlFlowLabel( insertIndex: Int, instructions: String, ) { @@ -298,7 +271,7 @@ fun Method.indexOfFirstResourceIdOrThrow(resourceName: String): Int { } /** - * Find the index of the first literal instruction with the given value. + * Find the index of the first literal instruction with the given long value. * * @return the first literal instruction with the value, or -1 if not found. * @see indexOfFirstLiteralInstructionOrThrow @@ -310,14 +283,56 @@ fun Method.indexOfFirstLiteralInstruction(literal: Long) = implementation?.let { } ?: -1 /** - * Find the index of the first literal instruction with the given value, + * Find the index of the first literal instruction with the given long value, * or throw an exception if not found. * * @return the first literal instruction with the value, or throws [PatchException] if not found. */ fun Method.indexOfFirstLiteralInstructionOrThrow(literal: Long): Int { val index = indexOfFirstLiteralInstruction(literal) - if (index < 0) throw PatchException("Could not find literal value: $literal") + if (index < 0) throw PatchException("Could not find long literal: $literal") + return index +} + +/** + * Find the index of the first literal instruction with the given float value. + * + * @return the first literal instruction with the value, or -1 if not found. + * @see indexOfFirstLiteralInstructionOrThrow + */ +fun Method.indexOfFirstLiteralInstruction(literal: Float) = + indexOfFirstLiteralInstruction(literal.toRawBits().toLong()) + +/** + * Find the index of the first literal instruction with the given float value, + * or throw an exception if not found. + * + * @return the first literal instruction with the value, or throws [PatchException] if not found. + */ +fun Method.indexOfFirstLiteralInstructionOrThrow(literal: Float): Int { + val index = indexOfFirstLiteralInstruction(literal) + if (index < 0) throw PatchException("Could not find float literal: $literal") + return index +} + +/** + * Find the index of the first literal instruction with the given double value. + * + * @return the first literal instruction with the value, or -1 if not found. + * @see indexOfFirstLiteralInstructionOrThrow + */ +fun Method.indexOfFirstLiteralInstruction(literal: Double) = + indexOfFirstLiteralInstruction(literal.toRawBits().toLong()) + +/** + * Find the index of the first literal instruction with the given double value, + * or throw an exception if not found. + * + * @return the first literal instruction with the value, or throws [PatchException] if not found. + */ +fun Method.indexOfFirstLiteralInstructionOrThrow(literal: Double): Int { + val index = indexOfFirstLiteralInstruction(literal) + if (index < 0) throw PatchException("Could not find double literal: $literal") return index } @@ -334,24 +349,80 @@ fun Method.indexOfFirstLiteralInstructionReversed(literal: Long) = implementatio } ?: -1 /** - * Find the index of the last wide literal instruction with the given value, + * Find the index of the last wide literal instruction with the given long value, * or throw an exception if not found. * * @return the last literal instruction with the value, or throws [PatchException] if not found. */ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Long): Int { val index = indexOfFirstLiteralInstructionReversed(literal) - if (index < 0) throw PatchException("Could not find literal value: $literal") + if (index < 0) throw PatchException("Could not find long literal: $literal") return index } /** - * Check if the method contains a literal with the given value. + * Find the index of the last literal instruction with the given float value. + * + * @return the last literal instruction with the value, or -1 if not found. + * @see indexOfFirstLiteralInstructionOrThrow + */ +fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) = + indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong()) + +/** + * Find the index of the last wide literal instruction with the given float value, + * or throw an exception if not found. + * + * @return the last literal instruction with the value, or throws [PatchException] if not found. + */ +fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Float): Int { + val index = indexOfFirstLiteralInstructionReversed(literal) + if (index < 0) throw PatchException("Could not find float literal: $literal") + return index +} + +/** + * Find the index of the last literal instruction with the given double value. + * + * @return the last literal instruction with the value, or -1 if not found. + * @see indexOfFirstLiteralInstructionOrThrow + */ +fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) = + indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong()) + +/** + * Find the index of the last wide literal instruction with the given double value, + * or throw an exception if not found. + * + * @return the last literal instruction with the value, or throws [PatchException] if not found. + */ +fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Double): Int { + val index = indexOfFirstLiteralInstructionReversed(literal) + if (index < 0) throw PatchException("Could not find double literal: $literal") + return index +} + +/** + * Check if the method contains a literal with the given long value. * * @return if the method contains a literal with the given value. */ fun Method.containsLiteralInstruction(literal: Long) = indexOfFirstLiteralInstruction(literal) >= 0 +/** + * Check if the method contains a literal with the given float value. + * + * @return if the method contains a literal with the given value. + */ +fun Method.containsLiteralInstruction(literal: Float) = indexOfFirstLiteralInstruction(literal) >= 0 + +/** + * Check if the method contains a literal with the given double value. + * + * @return if the method contains a literal with the given value. + */ +fun Method.containsLiteralInstruction(literal: Double) = indexOfFirstLiteralInstruction(literal) >= 0 + /** * Traverse the class hierarchy starting from the given root class. * @@ -565,7 +636,12 @@ fun Method.findInstructionIndicesReversedOrThrow(opcode: Opcode): List { return instructions } -internal fun MutableMethod.insertFeatureFlagBooleanOverride(literal: Long, extensionsMethod: String) { +/** + * Overrides the first move result with an extension call. + * Suitable for calls to extension code to override boolean and integer values. + */ +internal fun MutableMethod.insertLiteralOverride(literal: Long, extensionMethodDescriptor: String) { + // TODO: make this work with objects and wide values. val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) val index = indexOfFirstInstructionOrThrow(literalIndex, MOVE_RESULT) val register = getInstruction(index).registerA @@ -579,9 +655,24 @@ internal fun MutableMethod.insertFeatureFlagBooleanOverride(literal: Long, exten addInstructions( index + 1, """ - $operation, $extensionsMethod + $operation, $extensionMethodDescriptor move-result v$register - """, + """ + ) +} + +/** + * Overrides a literal value result with a constant value. + */ +internal fun MutableMethod.insertLiteralOverride(literal: Long, override: Boolean) { + val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) + val index = indexOfFirstInstructionOrThrow(literalIndex, MOVE_RESULT) + val register = getInstruction(index).registerA + val overrideValue = if (override) "0x1" else "0x0" + + addInstruction( + index + 1, + "const v$register, $overrideValue" ) } @@ -643,3 +734,58 @@ fun FingerprintBuilder.literal(literalSupplier: () -> Long) { method.containsLiteralInstruction(literalSupplier()) } } + +private class InstructionUtils { + companion object { + val branchOpcodes: EnumSet = EnumSet.of( + GOTO, GOTO_16, GOTO_32, + IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE, + IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ, + PACKED_SWITCH_PAYLOAD, SPARSE_SWITCH_PAYLOAD + ) + + val returnOpcodes: EnumSet = EnumSet.of( + RETURN_VOID, RETURN, RETURN_WIDE, RETURN_OBJECT, RETURN_VOID_NO_BARRIER, + THROW + ) + + val writeOpcodes: EnumSet = EnumSet.of( + ARRAY_LENGTH, + INSTANCE_OF, + NEW_INSTANCE, NEW_ARRAY, + MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, + MOVE_OBJECT_FROM16, MOVE_OBJECT_16, MOVE_RESULT, MOVE_RESULT_WIDE, MOVE_RESULT_OBJECT, MOVE_EXCEPTION, + CONST, CONST_4, CONST_16, CONST_HIGH16, CONST_WIDE_16, CONST_WIDE_32, + CONST_WIDE, CONST_WIDE_HIGH16, CONST_STRING, CONST_STRING_JUMBO, + IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, IGET_BYTE, IGET_CHAR, IGET_SHORT, + IGET_VOLATILE, IGET_WIDE_VOLATILE, IGET_OBJECT_VOLATILE, + SGET, SGET_WIDE, SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, SGET_CHAR, SGET_SHORT, + SGET_VOLATILE, SGET_WIDE_VOLATILE, SGET_OBJECT_VOLATILE, + AGET, AGET_WIDE, AGET_OBJECT, AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT, + // Arithmetic and logical operations. + ADD_DOUBLE_2ADDR, ADD_DOUBLE, ADD_FLOAT_2ADDR, ADD_FLOAT, ADD_INT_2ADDR, + ADD_INT_LIT8, ADD_INT, ADD_LONG_2ADDR, ADD_LONG, ADD_INT_LIT16, + AND_INT_2ADDR, AND_INT_LIT8, AND_INT_LIT16, AND_INT, AND_LONG_2ADDR, AND_LONG, + DIV_DOUBLE_2ADDR, DIV_DOUBLE, DIV_FLOAT_2ADDR, DIV_FLOAT, DIV_INT_2ADDR, + DIV_INT_LIT16, DIV_INT_LIT8, DIV_INT, DIV_LONG_2ADDR, DIV_LONG, + DOUBLE_TO_FLOAT, DOUBLE_TO_INT, DOUBLE_TO_LONG, + FLOAT_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, + INT_TO_BYTE, INT_TO_CHAR, INT_TO_DOUBLE, INT_TO_FLOAT, INT_TO_LONG, INT_TO_SHORT, + LONG_TO_DOUBLE, LONG_TO_FLOAT, LONG_TO_INT, + MUL_DOUBLE_2ADDR, MUL_DOUBLE, MUL_FLOAT_2ADDR, MUL_FLOAT, MUL_INT_2ADDR, + MUL_INT_LIT16, MUL_INT_LIT8, MUL_INT, MUL_LONG_2ADDR, MUL_LONG, + NEG_DOUBLE, NEG_FLOAT, NEG_INT, NEG_LONG, + NOT_INT, NOT_LONG, + OR_INT_2ADDR, OR_INT_LIT16, OR_INT_LIT8, OR_INT, OR_LONG_2ADDR, OR_LONG, + REM_DOUBLE_2ADDR, REM_DOUBLE, REM_FLOAT_2ADDR, REM_FLOAT, REM_INT_2ADDR, + REM_INT_LIT16, REM_INT_LIT8, REM_INT, REM_LONG_2ADDR, REM_LONG, + RSUB_INT_LIT8, RSUB_INT, + SHL_INT_2ADDR, SHL_INT_LIT8, SHL_INT, SHL_LONG_2ADDR, SHL_LONG, + SHR_INT_2ADDR, SHR_INT_LIT8, SHR_INT, SHR_LONG_2ADDR, SHR_LONG, + SUB_DOUBLE_2ADDR, SUB_DOUBLE, SUB_FLOAT_2ADDR, SUB_FLOAT, SUB_INT_2ADDR, + SUB_INT, SUB_LONG_2ADDR, SUB_LONG, + USHR_INT_2ADDR, USHR_INT_LIT8, USHR_INT, USHR_LONG_2ADDR, USHR_LONG, + XOR_INT_2ADDR, XOR_INT_LIT16, XOR_INT_LIT8, XOR_INT, XOR_LONG_2ADDR, XOR_LONG, + ) + } +} diff --git a/patches/src/main/resources/addresources/values-ar-rSA/strings.xml b/patches/src/main/resources/addresources/values-ar-rSA/strings.xml index bb2fa159a..b6befde99 100644 --- a/patches/src/main/resources/addresources/values-ar-rSA/strings.xml +++ b/patches/src/main/resources/addresources/values-ar-rSA/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" يجب أن يكون تعتيم التمرير السريع بين 0-100 مقدار حد التمرير الحد الأدنى من التمرير قبل اكتشاف الإيماءة + حساسية إيماءة تمرير مستوى الصوت + مقدار تغير مستوى الصوت لكل تمريرة عرض الواجهة الدائرية يتم عرض التراكب الدائري يتم عرض التراكب الأفقي diff --git a/patches/src/main/resources/addresources/values-az-rAZ/strings.xml b/patches/src/main/resources/addresources/values-az-rAZ/strings.xml index 8d8a12965..87a3e49a6 100644 --- a/patches/src/main/resources/addresources/values-az-rAZ/strings.xml +++ b/patches/src/main/resources/addresources/values-az-rAZ/strings.xml @@ -613,6 +613,9 @@ Bu seçimi dəyişdirmə işə düşmürsə, Gizli rejimə keçməyə çalışı Səs axını menyusu gizlidir Səs axını menyusu göstərilir + "Audio trek seçimi gizlədilib + +Audio trek seçimin göstərmək üçün \"Video axınları saxtalaşdır\"ı iOS TV-yə dəyiş" \"VR-da İzləni\" gizlət VR menyusunda izləmə gizlidir diff --git a/patches/src/main/resources/addresources/values-be-rBY/strings.xml b/patches/src/main/resources/addresources/values-be-rBY/strings.xml index 534e61a90..6df67c997 100644 --- a/patches/src/main/resources/addresources/values-be-rBY/strings.xml +++ b/patches/src/main/resources/addresources/values-be-rBY/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" Непразрыстасць пракруткі павінна быць паміж 0-100 Парог велічыні пальцам Велічыня парогавага значэння для правядзення пальцам + Адчувальнасць правядзення для гучнасці + Наколькі змяняецца гучнасць пры кожным правядзенні Паказваць кругавое накладанне Кругавое накладанне паказваецца Гарызантальнае накладанне паказваецца diff --git a/patches/src/main/resources/addresources/values-bg-rBG/strings.xml b/patches/src/main/resources/addresources/values-bg-rBG/strings.xml index c4612ed0d..43fdb2d37 100644 --- a/patches/src/main/resources/addresources/values-bg-rBG/strings.xml +++ b/patches/src/main/resources/addresources/values-bg-rBG/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" Непрозрачността на плъзгането трябва да е между 0-100 Праг на величината на плъзгане Праг преди да се осъществи плъзгането + Чувствителност при плъзгане за сила на звука + Колко се променя силата на звука при всяко плъзгане Показване на кръгъл овърлей Показва се кръгъл овърлей Показва се хоризонтален овърлей diff --git a/patches/src/main/resources/addresources/values-bn-rBD/strings.xml b/patches/src/main/resources/addresources/values-bn-rBD/strings.xml index c1f5c0ada..ecedc09f2 100644 --- a/patches/src/main/resources/addresources/values-bn-rBD/strings.xml +++ b/patches/src/main/resources/addresources/values-bn-rBD/strings.xml @@ -466,6 +466,8 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ সোয়াইপের অস্বচ্ছতা অবশ্যই 0-100 এর মধ্যে হতে হবে সোয়াইপ থ্রেশহোল্ড এর মাত্রা সোয়াইপ করার থ্রেশহোল্ডের পরিমাণ + ভলিউম সোয়াইপ সংবেদনশীলতা + প্রতি সোয়াইপে ভলিউম কতটা পরিবর্তিত হয় বৃত্তাকার ওভারলে দেখান বৃত্তাকার ওভারলে দেখানো হয়েছে অনুভূমিক ওভারলে দেখানো হয়েছে diff --git a/patches/src/main/resources/addresources/values-ca-rES/strings.xml b/patches/src/main/resources/addresources/values-ca-rES/strings.xml index c4424b0af..bb13abb74 100644 --- a/patches/src/main/resources/addresources/values-ca-rES/strings.xml +++ b/patches/src/main/resources/addresources/values-ca-rES/strings.xml @@ -466,6 +466,8 @@ Ajusteu el volum lliscant verticalment a la part dreta de la pantalla" L\'opacitat de lliscament ha d\'estar entre 0 i 100 Llindar de magnitud de lliscament La quantitat de llindar per a què es produeixi el desplaçament + Sensibilitat del lliscament de volum + Quant canvia el volum per lliscament Mostra la superposició circular Es mostra la superposició circular Es mostra la superposició horitzontal diff --git a/patches/src/main/resources/addresources/values-cs-rCZ/strings.xml b/patches/src/main/resources/addresources/values-cs-rCZ/strings.xml index db85ae868..378220b45 100644 --- a/patches/src/main/resources/addresources/values-cs-rCZ/strings.xml +++ b/patches/src/main/resources/addresources/values-cs-rCZ/strings.xml @@ -466,6 +466,8 @@ Hlasitost se upravuje svislým přejetím po pravé straně obrazovky" Průsvitnost tažení musí být mezi 0-100 Práh vynucení gesta Velikost prahu pro provedení gesta + Citlivost přejetí hlasitosti + O kolik se změní hlasitost na jedno přejetí Zobrazit kruhovou překryvnou vrstvu Zobrazuje se kruhová překryvná vrstva Zobrazuje se vodorovná překryvná vrstva diff --git a/patches/src/main/resources/addresources/values-da-rDK/strings.xml b/patches/src/main/resources/addresources/values-da-rDK/strings.xml index ba473455e..58f56d9c1 100644 --- a/patches/src/main/resources/addresources/values-da-rDK/strings.xml +++ b/patches/src/main/resources/addresources/values-da-rDK/strings.xml @@ -430,6 +430,8 @@ Juster lydstyrken ved at swipe lodret i højre side af skærmen" Gennemsigtighed for swipe skal være mellem 0-100 Stryg størrelse tærskel Beløbet for tærskelværdi for stryg der skal ske + Volumen strygefølsomhed + Hvor meget lydstyrken ændres pr. strygning Vis cirkulært overlejring Cirkulært overlejring vises Horisontalt overlejring vises diff --git a/patches/src/main/resources/addresources/values-de-rDE/strings.xml b/patches/src/main/resources/addresources/values-de-rDE/strings.xml index 0f463c51a..45b1790f2 100644 --- a/patches/src/main/resources/addresources/values-de-rDE/strings.xml +++ b/patches/src/main/resources/addresources/values-de-rDE/strings.xml @@ -459,6 +459,8 @@ Passen Sie die Helligkeit an, indem Sie auf der linken Seite des Bildschirms ver Die Wischdeckkraft muss zwischen 0 und 100 liegen Wischgrößenschwelle Der Schwellenwert für Wischen + Lautstärke-Wischgestenempfindlichkeit + Wie stark sich die Lautstärke pro Wisch ändert Kreisförmiges Overlay anzeigen Kreisförmiges Overlay wird angezeigt Horizontales Overlay wird angezeigt diff --git a/patches/src/main/resources/addresources/values-el-rGR/strings.xml b/patches/src/main/resources/addresources/values-el-rGR/strings.xml index a7c50c4a0..437d387a4 100644 --- a/patches/src/main/resources/addresources/values-el-rGR/strings.xml +++ b/patches/src/main/resources/addresources/values-el-rGR/strings.xml @@ -468,6 +468,8 @@ Second \"item\" text" Η αδιαφάνεια σάρωσης πρέπει να είναι μεταξύ 0-100 Κατώτατο όριο μεγέθους σάρωσης Η ελάχιστη απόσταση που θα διανύσετε με το δάκτυλο σας για να είναι αναγνωρίσιμη η χειρονομία σάρωσης + Ευαισθησία σάρωσης έντασης ήχου + Πόσο αλλάζει η ένταση ήχου ανά σάρωση Εμφάνιση κυκλικής διάταξης Η διάταξη των ελέγχων σάρωσης είναι κυκλική Η διάταξη των ελέγχων σάρωσης είναι οριζόντια diff --git a/patches/src/main/resources/addresources/values-es-rES/strings.xml b/patches/src/main/resources/addresources/values-es-rES/strings.xml index 7cab7ecc8..fe547ba7d 100644 --- a/patches/src/main/resources/addresources/values-es-rES/strings.xml +++ b/patches/src/main/resources/addresources/values-es-rES/strings.xml @@ -463,6 +463,8 @@ Ajusta el volumen deslizando verticalmente en el lado derecho de la pantalla"La opacidad de la superposición de deslizamiento debe estar entre 0 y 100 Umbral de magnitud del deslizamiento La cantidad de umbral para que se desliza + Sensibilidad del deslizamiento de volumen + Cuánto cambia el volumen por deslizamiento Mostrar superposición circular Se muestra la superposición circular Se muestra la superposición horizontal diff --git a/patches/src/main/resources/addresources/values-et-rEE/strings.xml b/patches/src/main/resources/addresources/values-et-rEE/strings.xml index 4ea3261bd..fcb5560a0 100644 --- a/patches/src/main/resources/addresources/values-et-rEE/strings.xml +++ b/patches/src/main/resources/addresources/values-et-rEE/strings.xml @@ -466,6 +466,8 @@ Helitugevuse reguleerimiseks pühkige ekraani paremal küljel vertikaalselt"Pühkiva katte läbipaistvus peab olema vahemikus 0-100 Pühkimise suuruse lävi Lävi väärtus pühkimise toimimiseks + Helitugevuse libistamise tundlikkus + Kui palju helitugevus ühe libistusega muutub Kuva ümmargune ülekattekiht Ümmargune ülekattekiht on nähtav Horisontaalne ülekattekiht on nähtav diff --git a/patches/src/main/resources/addresources/values-fi-rFI/strings.xml b/patches/src/main/resources/addresources/values-fi-rFI/strings.xml index 8466c1645..b99fa4c6b 100644 --- a/patches/src/main/resources/addresources/values-fi-rFI/strings.xml +++ b/patches/src/main/resources/addresources/values-fi-rFI/strings.xml @@ -466,6 +466,8 @@ Säädä äänenvoimakkuutta pyyhkäisemällä pystysuoraan näytön oikealta pu Pyyhkäisyn läpinäkymättömyyden on oltava välillä 0–100 Pyyhkäisyn kynnysraja Pyyhkäisyä varten tarvittavan kynnyksen määrä + Äänenvoimakkuuden pyyhkäisyn herkkyys + Kuinka paljon äänenvoimakkuus muuttuu pyyhkäisyä kohden Näytä pyöreä peittokuva Pyöreä peittokuva näytetään Vaakasuora peittokuva näytetään @@ -613,6 +615,9 @@ Jos tämän asetuksen muuttaminen ei tule voimaan, kokeile vaihtaa Incognito-til Ääniraitavalikko on piilotettu Ääniraitavalikko näytetään + "Ääniraitavalikko on piilotettu + +Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi" Piilota Katso VR-tilassa Katso VR-tilassa -valinta on piilotettu diff --git a/patches/src/main/resources/addresources/values-fil-rPH/strings.xml b/patches/src/main/resources/addresources/values-fil-rPH/strings.xml index aacfc28c8..180303332 100644 --- a/patches/src/main/resources/addresources/values-fil-rPH/strings.xml +++ b/patches/src/main/resources/addresources/values-fil-rPH/strings.xml @@ -466,6 +466,8 @@ Ayusin ang volume sa pamamagitan ng pag-swipe nang patayo sa kanang bahagi ng sc Ang opacity ng swipe ay dapat nasa pagitan ng 0-100 I-swipe ang magnitude threshold Ang halaga ng threshold para sa pag-swipe na magaganap + Pagkasensitibo sa pag-swipe ng volume + Gaano karami ang pagbabago ng volume sa bawat swipe Ipakita ang pabilog na overlay Ipinapakita ang pabilog na overlay Ipinapakita ang pahalang na overlay diff --git a/patches/src/main/resources/addresources/values-fr-rFR/strings.xml b/patches/src/main/resources/addresources/values-fr-rFR/strings.xml index 5fee9f945..63d199406 100644 --- a/patches/src/main/resources/addresources/values-fr-rFR/strings.xml +++ b/patches/src/main/resources/addresources/values-fr-rFR/strings.xml @@ -466,6 +466,8 @@ Réglez le volume en balayant verticalement sur le côté droit de l'écran"L\'opacité doit être comprise entre 0 et 100 pour les gestes Seuil d\'intensité des balayages L\'intensité du mouvement à effectuer pour qu\'un balayage soit pris en compte + Sensibilité du geste de contrôle du volume + Quantité de modification du volume à chaque balayage Afficher l\'overlay circulaire L\'overlay circulaire est affiché L\'overlay horizontal est affiché diff --git a/patches/src/main/resources/addresources/values-ga-rIE/strings.xml b/patches/src/main/resources/addresources/values-ga-rIE/strings.xml index f1f4f2c59..2f8693146 100644 --- a/patches/src/main/resources/addresources/values-ga-rIE/strings.xml +++ b/patches/src/main/resources/addresources/values-ga-rIE/strings.xml @@ -466,6 +466,8 @@ Coigeartaigh an toirt trí haisceartán go hingearach ar thaobh deas an scáile Caithfidh léaráidí traslaithe a bheith idir 0-100 Tairseach méid swipe Méid an tairseach le haghaidh sruthú tarlú + Íogaireacht swipe toirte + An méid a athraíonn an toirt in aghaidh gach swipe Taispeáin forleagan ciorclach Léirítear forleagan ciorclach Taispeántar forleagan cothrománach diff --git a/patches/src/main/resources/addresources/values-hu-rHU/strings.xml b/patches/src/main/resources/addresources/values-hu-rHU/strings.xml index f1576bf95..7cbcb428f 100644 --- a/patches/src/main/resources/addresources/values-hu-rHU/strings.xml +++ b/patches/src/main/resources/addresources/values-hu-rHU/strings.xml @@ -466,6 +466,8 @@ A hangerő a képernyő jobb oldalán függőlegesen húzva állítható be"A csúsztatás átlátszóságának 0 és 100 között kell lennie A csúsztatás küszöbértéke A csúsztatáshoz szükséges küszöbérték + Hangerő-görgetés érzékenysége + Mennyit változzon a hangerő görgetésenként Kör alakú fedvény megjelenítése Kör alakú fedvény megjelenik Vízszintes fedvény megjelenik diff --git a/patches/src/main/resources/addresources/values-hy-rAM/strings.xml b/patches/src/main/resources/addresources/values-hy-rAM/strings.xml index db77b233a..2425086db 100644 --- a/patches/src/main/resources/addresources/values-hy-rAM/strings.xml +++ b/patches/src/main/resources/addresources/values-hy-rAM/strings.xml @@ -466,6 +466,8 @@ MicroG-ի համար մարտկոցի օպտիմալացումը անջատել Սողալու անթափանցությունը պետք է լինի 0-100 միջակայքում Սահմանման վերածման չափը Սահմանման վերածման չափը + Ձայնի սահեցման զգայունություն + Թե որքան է ձայնի բարձրությունը փոխվում մեկ սահեցմամբ Ցույց տալ շրջանաձև ծածկույթը Ցուցադրված է շրջանաձև ծածկույթ Հորիզոնական ծածկույթը ցուցադրվում է diff --git a/patches/src/main/resources/addresources/values-in-rID/strings.xml b/patches/src/main/resources/addresources/values-in-rID/strings.xml index abaaeac98..0fc7c660a 100644 --- a/patches/src/main/resources/addresources/values-in-rID/strings.xml +++ b/patches/src/main/resources/addresources/values-in-rID/strings.xml @@ -466,6 +466,8 @@ Menyesuaikan volume dengan mengusap secara vertikal di sisi kanan layar"Opasitas geser harus antara 0-100 Ambang batas magnitudo usap Jumlah ambang batas untuk terjadinya usapan + Sensitivitas gesek volume + Seberapa besar perubahan volume per gesekan Tampilkan hamparan melingkar Hamparan melingkar ditampilkan Hamparan horizontal ditampilkan diff --git a/patches/src/main/resources/addresources/values-it-rIT/strings.xml b/patches/src/main/resources/addresources/values-it-rIT/strings.xml index c9f168e8c..a303d4813 100644 --- a/patches/src/main/resources/addresources/values-it-rIT/strings.xml +++ b/patches/src/main/resources/addresources/values-it-rIT/strings.xml @@ -466,6 +466,8 @@ Regola il volume scorrendo verticalmente sul lato destro dello schermo" L\'opacità di scorrimento deve essere tra 0-100 Ampiezza limite della soglia di scorrimento Il limite di ampiezza entro cui deve avvenire lo scorrimento + Sensibilità allo scorrimento del volume + La quantità di volume che cambia per scorrimento Mostra sovrapposizione circolare La sovrapposizione circolare viene mostrata La sovrapposizione orizzontale viene mostrata diff --git a/patches/src/main/resources/addresources/values-ja-rJP/strings.xml b/patches/src/main/resources/addresources/values-ja-rJP/strings.xml index ae5c6027a..53979f936 100644 --- a/patches/src/main/resources/addresources/values-ja-rJP/strings.xml +++ b/patches/src/main/resources/addresources/values-ja-rJP/strings.xml @@ -340,7 +340,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ キーワードを二重引用符で囲むことで、動画のタイトルやチャンネル名の単語の一部とキーワードが合致しないようにできます<br><br>例えば、<br><b>\"ai\"</b>は、次の動画を除外します:<b>How does AI work?</b><br>しかし、次の動画は除外しません:<b>What does fair use mean?</b> キーワードを使用できません: %s - キーワード %sを使用する引用符を追加 + キーワードを二重引用符で囲む必要があります: %s キーワードに矛盾する宣言があります: %s キーワードが短すぎるため二重引用符で囲む必要があります: %s キーワードはすべての動画を除外します: %s @@ -402,11 +402,11 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ URL をクリップボードにコピーしました タイムスタンプ付きの URL がコピーされました 「動画の URL をコピー」ボタンを表示 - オーバーレイ上にボタンが表示されます。タップすると動画の URL を、長押しするとタイムスタンプ付きの URL をそれぞれコピーできます - オーバーレイ上にボタンは表示されません + オーバーレイにボタンが表示されます。タップすると動画の URL を、長押しするとタイムスタンプ付きの URL をそれぞれコピーできます + オーバーレイにボタンは表示されません 「動画のタイムスタンプ付き URL をコピー」ボタンを表示 - オーバーレイ上にボタンが表示されます。タップするとタイムスタンプ付きの URL を、長押しするとタイムスタンプなしの URL をそれぞれコピーできます - オーバーレイ上にボタンは表示されません + オーバーレイにボタンが表示されます。タップするとタイムスタンプ付きの URL を、長押しするとタイムスタンプなしの URL をそれぞれコピーできます + オーバーレイにボタンは表示されません 「ご自身の責任」ダイアログを削除 @@ -418,8 +418,8 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ 外部ダウンロード 外部ダウンローダーの設定 外部ダウンロード ボタンを表示 - オーバーレイ上に外部ダウンロード ボタンが表示されます - オーバーレイ上に外部ダウンロード ボタンは表示されません + オーバーレイに外部ダウンロード ボタンが表示されます + オーバーレイに外部ダウンロード ボタンは表示されません オフライン ボタンの動作を上書きする オフライン ボタンは外部ダウンローダーを呼び出します @@ -465,10 +465,12 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ オーバーレイが表示される時間(ミリ秒) オーバーレイの背景の透明度 透明度の値は 0-100 の範囲で、0 が透明です - 透明度の値は 0-100 の間でなければなりません + スワイプ: 透明度の値は 0-100 でなければなりません スワイプのしきい値 スワイプと判定される最小の距離 - オーバーレイを円形にする + 音量ジェスチャーのスワイプ感度 + スワイプによる音量の変化量 + 円形のオーバーレイを使用する 円形のオーバーレイが表示されます 横長のオーバーレイが表示されます オーバーレイを最小限化する @@ -631,15 +633,15 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ 前の動画ボタンと次の動画ボタンは表示されません 前の動画ボタンと次の動画ボタンは表示されます キャスト ボタンを非表示 - オーバーレイ上にキャスト ボタンは表示されません - オーバーレイ上にキャスト ボタンが表示されます + オーバーレイにキャスト ボタンは表示されません + オーバーレイにキャスト ボタンが表示されます 字幕ボタンを非表示 - オーバーレイ上に字幕ボタンは表示されません - オーバーレイ上に字幕ボタンが表示されます + オーバーレイに字幕ボタンは表示されません + オーバーレイに字幕ボタンが表示されます 自動再生ボタンを非表示 - オーバーレイ上に自動再生ボタンは表示されません - オーバーレイ上に自動再生ボタンが表示されます + オーバーレイに自動再生ボタンは表示されません + オーバーレイに自動再生ボタンが表示されます 動画の終了画面を非表示 @@ -695,8 +697,8 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ チャンネル登録ボタンは表示されません チャンネル登録ボタンは表示されます 一時停止中のオーバーレイ上のボタンを非表示 - 一時停止中のオーバーレイ上のボタンは表示されません - 一時停止中のオーバーレイ上のボタンは表示されます + 一時停止中のオーバーレイにボタンは表示されません + 一時停止中のオーバーレイにボタンが表示されます ショップ ボタンを非表示 ショップ ボタンは表示されません ショップ ボタンは表示されます @@ -805,7 +807,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ オーバーレイの透明度 透明度の値は 0-100 の範囲で、0 が透明です - オーバーレイの透明度は 0-100 の間でなければなりません + プレーヤー: オーバーレイの透明度は 0-100 でなければなりません @@ -1201,7 +1203,7 @@ Automotive レイアウト ピクセル サイズの値は %1$s と %2$s の間でなければなりません オーバーレイの透明度 透明度の値は 0-100 の範囲で、0 が透明です - オーバーレイの透明度の値は 0-100 の間でなければなりません + ミニプレーヤー: オーバーレイの透明度は 0-100 でなければなりません グラデーション読み込み画面を有効にする @@ -1324,21 +1326,21 @@ Automotive レイアウト 画質の変更はすべての動画に適用されます 画質の変更は現在の動画にのみ適用されます デフォルトの画質(Wi-Fi) - デフォルトの画質(モバイル ネットワーク) - ショート動画の画質の変更を保存する + デフォルトの画質(携帯回線) + ショートの画質の変更を保存する 画質の変更はすべてのショート動画に適用されます 画質の変更は現在のショート動画にのみ適用されます - デフォルトのショート動画の画質(Wi-Fi) - デフォルトのショート動画の画質(モバイル ネットワーク) - モバイル ネットワーク + デフォルトのショートの画質(Wi-Fi) + デフォルトのショートの画質(携帯回線) + 携帯回線 Wi-Fi - デフォルトの画質 (%1$s) を %2$s に変更しました - ショート動画の画質 (%1$s) を %2$s に変更しました + デフォルトの画質 (%1$s): %2$s + ショートの画質 (%1$s): %2$s 再生速度設定ボタンを非表示 - オーバーレイ上に再生速度設定ボタンが表示されます - オーバーレイ上に再生速度設定ボタンは表示されません + オーバーレイに再生速度設定ボタンが表示されます + オーバーレイに再生速度設定ボタンは表示されません カスタムした再生速度リストを使用する @@ -1357,7 +1359,7 @@ Automotive レイアウト 再生速度の変更はすべての動画に適用されます 再生速度の変更は現在の動画にのみ適用されます デフォルトの再生速度 - デフォルトの再生速度を %s に変更しました + デフォルトの再生速度: %s HDR 動画を無効にする diff --git a/patches/src/main/resources/addresources/values-ko-rKR/strings.xml b/patches/src/main/resources/addresources/values-ko-rKR/strings.xml index f238b037a..d95d42ac1 100644 --- a/patches/src/main/resources/addresources/values-ko-rKR/strings.xml +++ b/patches/src/main/resources/addresources/values-ko-rKR/strings.xml @@ -465,6 +465,8 @@ MicroG 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배 스와이프 불투명도 값은 0-100 사이여야 합니다 스와이프 한계치 제스처 인식을 위해 얼마나 스와이프를 해야 할지를 지정할 수 있으며, 원하지 않은 제스처 인식을 방지할 수 있습니다 + 볼륨 스와이프 민감도 + 스와이프할 때마다 볼륨이 얼마나 변경되는지를 지정할 수 있습니다 원형 오버레이 표시하기 원형 오버레이를 표시합니다 바형 오버레이를 표시합니다 diff --git a/patches/src/main/resources/addresources/values-lt-rLT/strings.xml b/patches/src/main/resources/addresources/values-lt-rLT/strings.xml index 0b4c39d0c..64017bc9c 100644 --- a/patches/src/main/resources/addresources/values-lt-rLT/strings.xml +++ b/patches/src/main/resources/addresources/values-lt-rLT/strings.xml @@ -466,6 +466,8 @@ Reguliuokite garsumą braukdami vertikaliai dešinėje ekrano pusėje" Slinkties permatnumas turi būti nuo 0 iki 100 Slinkties dydžio slenkstis Slenkstis, reikalingas slinkčiai + Slinkimo garsumo jautrumas + Kiek garsumas pasikeičia per braukimą Rodyti apskritą perdangą Rodoma apskrita perdanga Rodoma horizontali perdanga diff --git a/patches/src/main/resources/addresources/values-lv-rLV/strings.xml b/patches/src/main/resources/addresources/values-lv-rLV/strings.xml index 8f9412d8d..863676ed6 100644 --- a/patches/src/main/resources/addresources/values-lv-rLV/strings.xml +++ b/patches/src/main/resources/addresources/values-lv-rLV/strings.xml @@ -466,6 +466,8 @@ Regulējiet skaļumu, velkot vertikāli ekrāna labajā pusē" Pārvilkšanas necaurredzamībai jābūt no 0 līdz 100 Slīdēšanas lieluma slieksnis Slieksnis, lai slīdēšana varētu notikt + Svilpes jutīgums skaļuma regulēšanai + Cik daudz skaļums mainās ar katru vilkšanu Rādīt apļveida pārklājumu Apļveida pārklājums tiek rādīts Horizontālais pārklājums tiek rādīts diff --git a/patches/src/main/resources/addresources/values-nl-rNL/strings.xml b/patches/src/main/resources/addresources/values-nl-rNL/strings.xml index 1be4e0569..872c04b78 100644 --- a/patches/src/main/resources/addresources/values-nl-rNL/strings.xml +++ b/patches/src/main/resources/addresources/values-nl-rNL/strings.xml @@ -466,6 +466,8 @@ Pas het volume aan door verticaal over de rechterkant van het scherm te vegen"Dekking moet tussen 0-100 zijn Drempelwaarde swipe-sterkte De hoeveelheid drempelwaarde voor swipe om te gebeuren + Gevoeligheid volumegest + Hoeveel het volume verandert per swipe Circulaire overlay weergeven Circulaire overlay wordt weergegeven Horizontale overlay wordt weergegeven diff --git a/patches/src/main/resources/addresources/values-pl-rPL/strings.xml b/patches/src/main/resources/addresources/values-pl-rPL/strings.xml index 557c08bce..0996ca777 100644 --- a/patches/src/main/resources/addresources/values-pl-rPL/strings.xml +++ b/patches/src/main/resources/addresources/values-pl-rPL/strings.xml @@ -466,6 +466,8 @@ Dostosuj głośność, przesuwając pionowo po prawej stronie ekranu" Przezroczystość przesuwania musi być między 0 a 100 Minimalna długość przesunięcia Wartość wymagana do wykonania gestu przesunięcia + Czułość przesunięcia głośności + O ile zmienia się głośność na przesunięcie Pokaż okrągłą nakładkę Wyświetlana jest okrągła nakładka Wyświetlana jest pozioma nakładka diff --git a/patches/src/main/resources/addresources/values-pt-rBR/strings.xml b/patches/src/main/resources/addresources/values-pt-rBR/strings.xml index 257354aed..4a9c725a0 100644 --- a/patches/src/main/resources/addresources/values-pt-rBR/strings.xml +++ b/patches/src/main/resources/addresources/values-pt-rBR/strings.xml @@ -464,6 +464,8 @@ Ajuste o volume deslizando verticalmente no lado direito da tela" A opacidade do deslizar deve estar entre 0-100 Limiar distância no gesto Quantidade limite que o gesto irá ocorrer + Sensibilidade ao deslizar o volume + O quanto o volume muda por deslize Mostrar sobreposição circular A sobreposição circular é mostrada A sobreposição horizontal é mostrada diff --git a/patches/src/main/resources/addresources/values-pt-rPT/strings.xml b/patches/src/main/resources/addresources/values-pt-rPT/strings.xml index 1e0b53d0e..42e70f2a0 100644 --- a/patches/src/main/resources/addresources/values-pt-rPT/strings.xml +++ b/patches/src/main/resources/addresources/values-pt-rPT/strings.xml @@ -466,6 +466,8 @@ Ajuste o volume deslizando verticalmente no lado direito da tela" A opacidade do deslizar deve estar entre 0-100 Limite de magnitude A quantidade limite para deslizar irá ocorrer + Sensibilidade ao deslizar o volume + O quanto o volume muda por deslize Mostrar sobreposição circular A sobreposição circular é mostrada A sobreposição horizontal é mostrada diff --git a/patches/src/main/resources/addresources/values-ro-rRO/strings.xml b/patches/src/main/resources/addresources/values-ro-rRO/strings.xml index 6db882d86..7b7150228 100644 --- a/patches/src/main/resources/addresources/values-ro-rRO/strings.xml +++ b/patches/src/main/resources/addresources/values-ro-rRO/strings.xml @@ -466,6 +466,8 @@ Reglați volumul glisând vertical pe partea dreaptă a ecranului" Opacitatea glisării trebuie să fie între 0-100 Pragul mărimii glisării Cantitatea de prag pentru a glisa + Sensibilitate glisare volum + Cât de mult se modifică volumul per glisare Afișează suprapunerea circulară Suprapunerea circulară este afișată Suprapunerea orizontală este afișată diff --git a/patches/src/main/resources/addresources/values-ru-rRU/strings.xml b/patches/src/main/resources/addresources/values-ru-rRU/strings.xml index 05f608356..a99ceb838 100644 --- a/patches/src/main/resources/addresources/values-ru-rRU/strings.xml +++ b/patches/src/main/resources/addresources/values-ru-rRU/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" Значение затемнения панели жестов должно быть от 0 до 100 Порог величины жеста Минимальная амплитуда движения, распознаваемого как жест + Чувствительность свайпа для регулировки громкости + На сколько изменяется громкость при каждом свайпе Показать круговой индикатор Круговой индикатор показан Горизонтальный индикатор показан diff --git a/patches/src/main/resources/addresources/values-sk-rSK/strings.xml b/patches/src/main/resources/addresources/values-sk-rSK/strings.xml index ced887dff..e619f3a3b 100644 --- a/patches/src/main/resources/addresources/values-sk-rSK/strings.xml +++ b/patches/src/main/resources/addresources/values-sk-rSK/strings.xml @@ -459,6 +459,8 @@ Upravte hlasitosť posúvaním vertikálne na pravej strane obrazovky" Priehľadnosť prekrytia potiahnutia musí byť medzi 0-100 Prahová hodnota potiahnutia Hodnota prahu, ktorý sa má vykonať potiahnutím prstom + Citlivosť posúvania hlasitosti + Ako veľmi sa mení hlasitosť na jedno posunutie Zobraziť kruhovú vrstvu Kruhová vrstva sa zobrazuje Zobrazuje sa vodorovná vrstva diff --git a/patches/src/main/resources/addresources/values-sl-rSI/strings.xml b/patches/src/main/resources/addresources/values-sl-rSI/strings.xml index c02eff6b2..8f3c4ffd0 100644 --- a/patches/src/main/resources/addresources/values-sl-rSI/strings.xml +++ b/patches/src/main/resources/addresources/values-sl-rSI/strings.xml @@ -466,6 +466,8 @@ Prilagodite glasnost s potegom navpično na desni strani zaslona" Prosojnost drsenja mora biti med 0 in 100 Prazg prag za pomikanje Vrednost praga za pomikanje + Občutljivost drsenja za glasnost + Koliko se spremeni glasnost na poteg Pokaži krožni prekrivni element Krožni prekrivni element je prikazan Prikazan je vodoravni prekrivni element diff --git a/patches/src/main/resources/addresources/values-sq-rAL/strings.xml b/patches/src/main/resources/addresources/values-sq-rAL/strings.xml index 8681e250e..fa2fd0e2a 100644 --- a/patches/src/main/resources/addresources/values-sq-rAL/strings.xml +++ b/patches/src/main/resources/addresources/values-sq-rAL/strings.xml @@ -466,6 +466,8 @@ Përshtate shkëlqimin duke rrëshqitur vertikalisht në anën e majtë të ekra Opaciteti i shtypjes duhet të jetë midis 0-100 Pragu i madhësisë së shërbimit Sasia e pragut për të ndodhur shërbimi + Ndjeshmëria e rrëshqitjes së volumit + Sa ndryshon volumi për rrëshqitje Shfaq mbivendosjen rrethore Mbivendosja rrethore është shfaqur Mbivendosja horizontale është shfaqur diff --git a/patches/src/main/resources/addresources/values-sr-rCS/strings.xml b/patches/src/main/resources/addresources/values-sr-rCS/strings.xml index 82ffd09ae..5bed5f3a1 100644 --- a/patches/src/main/resources/addresources/values-sr-rCS/strings.xml +++ b/patches/src/main/resources/addresources/values-sr-rCS/strings.xml @@ -466,6 +466,8 @@ Podesite jačinu zvuka prevlačenjem vertikalno na desnoj strani ekrana"Neprozirnost pokreta prevlačenja mora biti između 0 i 100 Prag trajanja prevlačenja Iznos praga trajanja prevlačenja + Osetljivost prevlačenja za jačinu zvuka + Koliko se jačina zvuka menja po prevlačenju Prikaži kružni preklop Prikazan je kružni preklop Prikazan je horizontalni preklop diff --git a/patches/src/main/resources/addresources/values-sr-rSP/strings.xml b/patches/src/main/resources/addresources/values-sr-rSP/strings.xml index 892604f7c..381ee10ab 100644 --- a/patches/src/main/resources/addresources/values-sr-rSP/strings.xml +++ b/patches/src/main/resources/addresources/values-sr-rSP/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" Непрозирност покрета превлачења мора бити између 0 и 100 Праг трајања превлачења Износ прага трајања превлачења + Осетљивост покрета за јачину звука + Колико се јачина звука мења по покрету Прикажи кружни преклоп Приказан је кружни преклоп Приказан је хоризонтални преклоп diff --git a/patches/src/main/resources/addresources/values-sv-rSE/strings.xml b/patches/src/main/resources/addresources/values-sv-rSE/strings.xml index a9e5312f6..a1b358ee0 100644 --- a/patches/src/main/resources/addresources/values-sv-rSE/strings.xml +++ b/patches/src/main/resources/addresources/values-sv-rSE/strings.xml @@ -466,6 +466,8 @@ Justera volymen genom att svepa vertikalt på höger sida av skärmen" Överlagrad svepopacitet måste vara mellan 0-100 Svep magnitud tröskel Mängden tröskel för att svepa ska uppstå + Volym svepkänslighet + Hur mycket volymen ändras per svep Visa cirkelformad overlay Cirkelformad overlay visas Horisontell overlay visas diff --git a/patches/src/main/resources/addresources/values-th-rTH/strings.xml b/patches/src/main/resources/addresources/values-th-rTH/strings.xml index 398c55ecb..82c4504cb 100644 --- a/patches/src/main/resources/addresources/values-th-rTH/strings.xml +++ b/patches/src/main/resources/addresources/values-th-rTH/strings.xml @@ -464,6 +464,8 @@ Second \"item\" text" ค่าความทึบแสงของสไลด์ต้องอยู่ระหว่าง 0-100 เกณฑ์ขนาดของการปัด จำนวนเกณฑ์สำหรับการปัดที่จะเกิดขึ้น + ความไวในการปัดปรับระดับเสียง + ปริมาณการเปลี่ยนแปลงระดับเสียงต่อการปัดแต่ละครั้ง แสดงภาพซ้อนทับแบบวงกลม แสดงภาพซ้อนทับแบบวงกลม แสดงภาพซ้อนทับแนวนอน diff --git a/patches/src/main/resources/addresources/values-tr-rTR/strings.xml b/patches/src/main/resources/addresources/values-tr-rTR/strings.xml index 13af33db0..b813cd458 100644 --- a/patches/src/main/resources/addresources/values-tr-rTR/strings.xml +++ b/patches/src/main/resources/addresources/values-tr-rTR/strings.xml @@ -466,6 +466,8 @@ Ekranın sağ tarafında dikey olarak kaydırarak sesi ayarlayın" Kaydırma opaklığı 0-100 arasında olmalıdır Kaydırma büyüklük eşiği Kaydırma işleminin gerçekleşmesi için eşik miktarı + Ses kaydırma hassasiyeti + Kaydırma başına sesin ne kadar değişeceği Dairesel katmanı göster Dairesel katman gösteriliyor Yatay katman gösteriliyor diff --git a/patches/src/main/resources/addresources/values-uk-rUA/strings.xml b/patches/src/main/resources/addresources/values-uk-rUA/strings.xml index ad9e0b6a5..25f93b4f9 100644 --- a/patches/src/main/resources/addresources/values-uk-rUA/strings.xml +++ b/patches/src/main/resources/addresources/values-uk-rUA/strings.xml @@ -466,6 +466,8 @@ Second \"item\" text" Значення затемнення панелі жесту має бути в межах від 0 до 100 Поріг величини жесту Мінімальна амплітуда руху, що розпізнається як жест + Чутливість гортання гучності + На скільки змінюється гучність за одне гортання Показувати круговий індикатор Показується круговий індикатор Показується горизонтальний індикатор diff --git a/patches/src/main/resources/addresources/values-vi-rVN/strings.xml b/patches/src/main/resources/addresources/values-vi-rVN/strings.xml index 95f94fa2f..1a03eb34f 100644 --- a/patches/src/main/resources/addresources/values-vi-rVN/strings.xml +++ b/patches/src/main/resources/addresources/values-vi-rVN/strings.xml @@ -466,6 +466,8 @@ Tính năng này chỉ khả dụng cho các thiết bị cũ hơn" Độ mờ vuốt phải nằm trong khoảng từ 0-100 Độ rộng ngưỡng vuốt Độ rộng của ngưỡng vuốt để thực hiện cử chỉ vuốt + Độ nhạy vuốt âm lượng + Mức âm lượng thay đổi trên mỗi lần vuốt Hiện lớp phủ hình tròn Lớp phủ tròn được hiện Lớp phủ ngang được hiện diff --git a/patches/src/main/resources/addresources/values-zh-rCN/strings.xml b/patches/src/main/resources/addresources/values-zh-rCN/strings.xml index 632e7c87d..36bd238b7 100644 --- a/patches/src/main/resources/addresources/values-zh-rCN/strings.xml +++ b/patches/src/main/resources/addresources/values-zh-rCN/strings.xml @@ -459,19 +459,21 @@ Second \"item\" text" 启用自动亮度手势 滑动到最低亮度手势将启用自动亮度 滑动到最低亮度手势不启用自动亮度 - 滑动覆盖超时 - 滑动叠加层显示的时长(毫秒) - 滑动叠加层背景的不透明度 + 滑动提示层显示时长 + 滑动提示的显示时长(毫秒) + 滑动提示层背景的不透明度 不透明度值介于 0-100 之间 滑动不透明度必须介于 0-100 之间 滑动幅度阈值 防误触的滑动幅度阈值 - 显示圆形叠加层 - 圆形叠加层已显示 - 水平叠加层已显示 - 启用极简样式 - 已启用极简叠加样式 - 已停用最小叠加层样式 + 音量滑动灵敏度 + 每次滑动音量变化的幅度 + 圆形的叠加层样式 + 提示层显示为圆形样式 + 提示层显示为水平样式 + 极简提示样式 + 极简样式已启用 + 极简样式已禁用 启用滑动切换视频 在全屏模式下滑动将切换到下一个/上一个视频 在全屏模式下滑动将不会切换到下一个/上一个视频 @@ -882,9 +884,9 @@ Second \"item\" text" 显示投票按钮 显示片段投票按钮 不显示片段投票按钮 - 使用方形布局 - 使用方形的按钮和控件 - 使用圆角的按钮和控件 + 使用方形控件 + 使用方形样式的按钮和控件 + 使用圆角样式的按钮和控件 使用紧凑的跳过按钮 跳过按钮样式为最小宽度 diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 3d8330396..af43602b4 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -527,6 +527,8 @@ Adjust volume by swiping vertically on the right side of the screen" Swipe opacity must be between 0-100 Swipe magnitude threshold The amount of threshold for swipe to occur + Volume swipe sensitivity + How much the volume changes per swipe Show circular overlay Circular overlay is shown Horizontal overlay is shown