Compare commits

...

38 Commits

Author SHA1 Message Date
semantic-release-bot
b8c2ede2bf chore: Release v5.44.0-dev.4 [skip ci]
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)

### Features

* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](e7336d2ef3))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](591e106098))
2025-10-24 05:32:12 +00:00
hckrman101
591e106098 feat(Duolingo): Add Skip energy recharge ads patch (#6167) 2025-10-24 09:28:34 +04:00
Pawloland
e7336d2ef3 feat: Add Custom network security patch (#6151) 2025-10-24 09:27:12 +04:00
LisoUseInAIKyrios
7a53f8f62d chore(YouTube Music): Simplify fingerprint for upcoming app versions 2025-10-24 09:25:44 +04:00
github-actions[bot]
3466d9d210 chore: Sync translations (#6172) 2025-10-24 09:19:08 +04:00
LisoUseInAIKyrios
876d7a6b03 chore(X / Twitter - Change link sharing domain): Add disclaimer to description 2025-10-24 09:18:20 +04:00
semantic-release-bot
a2aa9cac27 chore: Release v5.44.0-dev.3 [skip ci]
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)

### Features

* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](08baa19b4a))
2025-10-22 20:24:37 +00:00
LisoUseInAIKyrios
08baa19b4a feat(Duolingo - Enable debug menu): Support latest app target (#6163) 2025-10-23 00:21:30 +04:00
semantic-release-bot
7283b93cea chore: Release v5.44.0-dev.2 [skip ci]
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)

### Bug Fixes

* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](754b71959a))
2025-10-22 16:53:15 +00:00
Lassie111
754b71959a fix(Google Photos - Spoof features): Add support for Pixel 10 devices (#6161) 2025-10-22 20:50:10 +04:00
LisoUseInAIKyrios
c64e29ec57 refactor(YouTube - Seekbar): Remove obsolete splash screen color code 2025-10-22 11:47:39 +04:00
semantic-release-bot
b2dd008aee chore: Release v5.44.0-dev.1 [skip ci]
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)

### Features

* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](de97562c5d))
2025-10-22 06:14:00 +00:00
rospino74
de97562c5d feat(Samsung Radio): Add Disable device checks patch (#6145) 2025-10-22 10:09:34 +04:00
semantic-release-bot
6373829fd6 chore: Release v5.43.2-dev.3 [skip ci]
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)

### Bug Fixes

* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](cfd244b408))
2025-10-19 14:29:38 +00:00
Bceez
cfd244b408 fix(YouTube - Hide layout components): Hide new kind of community post (#6146) 2025-10-19 18:24:45 +04:00
semantic-release-bot
e8e28e2b6a chore: Release v5.43.2-dev.2 [skip ci]
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)

### Bug Fixes

* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](2e4c6fdcad))
2025-10-17 21:15:51 +00:00
LisoUseInAIKyrios
2e4c6fdcad fix(YouTube Music): Resolve patching 7.29 target 2025-10-18 01:12:34 +04:00
github-actions[bot]
644d6dcb51 chore: Sync translations (#6142) 2025-10-18 01:08:27 +04:00
semantic-release-bot
14dd7346a8 chore: Release v5.43.2-dev.1 [skip ci]
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](0af8c8a766))
2025-10-16 19:37:32 +00:00
ADudeCalledLeo
0af8c8a766 fix(X / Twitter - Change link sharing domain): Use bytecode patching to resolve patching with Manager (#6125) 2025-10-16 23:29:01 +04:00
semantic-release-bot
96454c843b chore: Release v5.43.1 [skip ci]
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](7563990750))
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](2a1e31860f))
2025-10-15 08:15:15 +00:00
LisoUseInAIKyrios
476ef0fae1 chore: Merge branch dev to main (#6121) 2025-10-15 12:12:25 +04:00
github-actions[bot]
bbec724afb chore: Sync translations (#6124) 2025-10-15 12:11:47 +04:00
semantic-release-bot
7a1dcbd4ee chore: Release v5.43.1-dev.2 [skip ci]
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)

### Bug Fixes

* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](2a1e31860f))
2025-10-14 19:47:15 +00:00
LisoUseInAIKyrios
2a1e31860f fix(X / Twitter): Do not crash Manager when clicking on domain patch option 2025-10-14 23:42:15 +04:00
semantic-release-bot
949d6bdd19 chore: Release v5.43.1-dev.1 [skip ci]
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](7563990750))
2025-10-14 18:19:42 +00:00
ADudeCalledLeo
7563990750 fix(X / Twitter - Change link sharing domain): Resolve duplicate patch option (#6119) 2025-10-14 22:16:01 +04:00
semantic-release-bot
4b605eb270 chore: Release v5.43.0 [skip ci]
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)

### Bug Fixes

* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](95eee59a87))
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](be2b144cc9))
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](54846253d7))
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](6555f6e6f8))
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](10ea250d4a))
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](0c19dbaf30))

### Features

* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](50f0b9c5ee))
2025-10-14 12:03:58 +00:00
LisoUseInAIKyrios
c2d7a7fb8b chore: Merge branch dev to main (#6090) 2025-10-14 16:00:00 +04:00
github-actions[bot]
a55560dc25 chore: Sync translations (#6118) 2025-10-14 15:58:38 +04:00
semantic-release-bot
e8522d703e chore: Release v5.43.0-dev.4 [skip ci]
# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14)

### Bug Fixes

* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](0c19dbaf30))
2025-10-14 11:46:49 +00:00
LisoUseInAIKyrios
068d029a03 refactor: Use notNull delegate to prevent wasting more time in the future 2025-10-14 15:43:05 +04:00
LisoUseInAIKyrios
0c19dbaf30 fix(YouTube - Force original audio): Do not use translated audio if stream spoofing is off and force audio is on 2025-10-14 15:38:05 +04:00
semantic-release-bot
bf73ac8316 chore: Release v5.43.0-dev.3 [skip ci]
# [5.43.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.2...v5.43.0-dev.3) (2025-10-14)

### Bug Fixes

* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](95eee59a87))
2025-10-14 10:39:28 +00:00
LisoUseInAIKyrios
95eee59a87 fix(Custom branding): Use white notification icon for expanded status bar panel 2025-10-14 14:36:09 +04:00
semantic-release-bot
566875ea53 chore: Release v5.43.0-dev.2 [skip ci]
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)

### Bug Fixes

* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](10ea250d4a))
2025-10-14 05:58:15 +00:00
LisoUseInAIKyrios
10ea250d4a fix(YouTube - Custom branding): Use ReVanced icon for status bar notification icon (#6108) 2025-10-14 09:54:14 +04:00
github-actions[bot]
5bd0f11630 chore: Sync translations (#6117) 2025-10-14 09:53:13 +04:00
61 changed files with 1683 additions and 1011 deletions

View File

@@ -1,3 +1,113 @@
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)
### Features
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)
### Features
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)
### Bug Fixes
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)
### Features
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)
### Bug Fixes
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)
### Bug Fixes
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)
### Bug Fixes
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)
### Bug Fixes
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b))
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2))
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12))
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
### Features
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14)
### Bug Fixes
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
# [5.43.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.2...v5.43.0-dev.3) (2025-10-14)
### Bug Fixes
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)
### Bug Fixes
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
# [5.43.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.3...v5.43.0-dev.1) (2025-10-11)

View File

@@ -5,8 +5,10 @@ import android.preference.PreferenceScreen;
import android.widget.Toolbar;
import app.revanced.extension.music.settings.MusicActivityHook;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
/**
@@ -30,6 +32,17 @@ public class MusicPreferenceFragment extends ToolbarPreferenceFragment {
preferenceScreen = getPreferenceScreen();
Utils.sortPreferenceGroups(preferenceScreen);
setPreferenceScreenToolbar(preferenceScreen);
// Clunky work around until preferences are custom classes that manage themselves.
// Custom branding only works with non-root install. But the preferences must be
// added during patched because of difficulties detecting during patching if it's
// a root install. So instead the non-functional preferences are removed during
// runtime if the app is mount (root) installation.
if (GmsCoreSupport.isPackageNameOriginal()) {
removePreferences(
BaseSettings.CUSTOM_BRANDING_ICON.key,
BaseSettings.CUSTOM_BRANDING_NAME.key);
}
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}

View File

@@ -0,0 +1,4 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:samsung:radio:stub"))
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,24 @@
package app.revanced.extension.samsung.radio.misc.fix.crash;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SuppressWarnings("unused")
public final class FixCrashPatch {
/**
* Injection point.
* <p>
* Add the required permissions to the request list to avoid crashes on API 34+.
**/
public static final String[] fixPermissionRequestList(String[] perms) {
List<String> permsList = new ArrayList<>(Arrays.asList(perms));
if (permsList.contains("android.permission.POST_NOTIFICATIONS")) {
permsList.addAll(Arrays.asList("android.permission.RECORD_AUDIO", "android.permission.READ_PHONE_STATE", "android.permission.FOREGROUND_SERVICE_MICROPHONE"));
}
if (permsList.contains("android.permission.RECORD_AUDIO")) {
permsList.add("android.permission.FOREGROUND_SERVICE_MICROPHONE");
}
return permsList.toArray(new String[0]);
}
}

View File

@@ -0,0 +1,19 @@
package app.revanced.extension.samsung.radio.restrictions.device;
import android.os.SemSystemProperties;
import java.util.Arrays;
@SuppressWarnings("unused")
public final class BypassDeviceChecksPatch {
/**
* Injection point.
* <p>
* Check if the device has the required hardware
**/
public static final boolean checkIfDeviceIsIncompatible(String[] deviceList) {
String currentDevice = SemSystemProperties.getSalesCode();
return Arrays.asList(deviceList).contains(currentDevice);
}
}

View File

@@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "app.revanced.extension"
compileSdk = 34
defaultConfig {
minSdk = 24
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,7 @@
package android.os;
public class SemSystemProperties {
public static String getSalesCode() {
throw new UnsupportedOperationException("Stub");
}
}

View File

@@ -1,11 +1,14 @@
package app.revanced.extension.shared.patches;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger;
@@ -29,28 +32,56 @@ public class CustomBrandingPatch {
// The most that can be done is to hide a theme from the UI and keep the alias with dummy data.
public enum BrandingTheme {
/**
* Original unpatched icon. Must be first enum.
* Original unpatched icon.
*/
ORIGINAL("revanced_original"),
ROUNDED("revanced_rounded"),
MINIMAL("revanced_minimal"),
SCALED("revanced_scaled"),
ORIGINAL,
ROUNDED,
MINIMAL,
SCALED,
/**
* User provided custom icon. Must be the last enum.
* User provided custom icon.
*/
CUSTOM("revanced_custom");
public final String themeAlias;
BrandingTheme(String themeAlias) {
this.themeAlias = themeAlias;
}
CUSTOM;
private String packageAndNameIndexToClassAlias(String packageName, int appIndex) {
if (appIndex <= 0) {
throw new IllegalArgumentException("App index starts at index 1");
}
return packageName + '.' + themeAlias + '_' + appIndex;
return packageName + ".revanced_" + name().toLowerCase(Locale.US) + '_' + appIndex;
}
}
private static final int notificationSmallIcon;
static {
BrandingTheme branding = BaseSettings.CUSTOM_BRANDING_ICON.get();
if (branding == BrandingTheme.ORIGINAL) {
notificationSmallIcon = 0;
} else {
// Original icon is quantum_ic_video_youtube_white_24
String iconName = "revanced_notification_icon";
if (branding == BrandingTheme.CUSTOM) {
iconName += "_custom";
}
notificationSmallIcon = Utils.getResourceIdentifier(iconName, "drawable");
if (notificationSmallIcon == 0) {
Logger.printException(() -> "Could not load notification small icon");
}
}
}
/**
* Injection point.
*/
public static void setNotificationIcon(Notification.Builder builder) {
try {
if (notificationSmallIcon != 0) {
builder.setSmallIcon(notificationSmallIcon)
.setColor(Color.TRANSPARENT); // Remove YT red tint.
}
} catch (Exception ex) {
Logger.printException(() -> "setNotificationIcon failure", ex);
}
}

View File

@@ -6,6 +6,7 @@ import android.graphics.Insets;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.util.TypedValue;
import android.view.ViewGroup;
@@ -22,6 +23,24 @@ import app.revanced.extension.shared.settings.BaseActivityHook;
@SuppressWarnings({"deprecation", "NewApi"})
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
/**
* Removes the list of preferences from this fragment, if they exist.
* @param keys Preference keys.
*/
protected void removePreferences(String ... keys) {
for (String key : keys) {
Preference pref = findPreference(key);
if (pref != null) {
PreferenceGroup parent = pref.getParent();
if (parent != null) {
Logger.printDebug(() -> "Removing preference: " + key);
parent.removePreference(pref);
}
}
}
}
/**
* Sets toolbar for all nested preference screens.
*/

View File

@@ -2,7 +2,7 @@ package app.revanced.twitter.patches.links;
@SuppressWarnings("unused")
public final class ChangeLinkSharingDomainPatch {
private static final String LINK_FORMAT = "%s/%s/status/%s";
private static final String LINK_FORMAT = "https://%s/%s/status/%s";
/**
* Method is modified during patching. Do not change.
@@ -11,6 +11,16 @@ public final class ChangeLinkSharingDomainPatch {
return "";
}
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
/**
* Injection point.
*/
public static String formatResourceLink(Object... formatArgs) {
String username = (String) formatArgs[0];
String tweetId = (String) formatArgs[1];
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
}
/**
* Injection point.
*/

View File

@@ -87,7 +87,8 @@ public final class LayoutComponentsFilter extends Filter {
"post_shelf_slim.e",
"videos_post_responsive_root.e",
"text_post_responsive_root.e",
"poll_post_responsive_root.e"
"poll_post_responsive_root.e",
"shared_post_root.e"
);
final var subscribersCommunityGuidelines = new StringFilterGroup(

View File

@@ -1,51 +0,0 @@
package app.revanced.extension.youtube.patches.theme;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.youtube.patches.HideSeekbarPatch;
import app.revanced.extension.youtube.settings.Settings;
/**
* Used by {@link SeekbarColorPatch} change the color of the seekbar.
* and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history.
*/
@SuppressWarnings("unused")
public class ProgressBarDrawable extends Drawable {
private final Paint paint = new Paint();
{
paint.setColor(SeekbarColorPatch.getSeekbarColor());
}
@Override
public void draw(@NonNull Canvas canvas) {
if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) {
return;
}
canvas.drawRect(getBounds(), paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@@ -4,9 +4,7 @@ import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.clamp;
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.AnimatedVectorDrawable;
import com.airbnb.lottie.LottieAnimationView;
@@ -15,7 +13,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Locale;
import java.util.Scanner;
import app.revanced.extension.shared.Logger;
@@ -104,27 +101,6 @@ public final class SeekbarColorPatch {
return customSeekbarColor;
}
private static int colorChannelTo3Bits(int channel8Bits) {
final float channel3Bits = channel8Bits * 7 / 255f;
// If a color channel is near zero, then allow rounding up so values between
// 0x12 and 0x23 will show as 0x24. But always round down when the channel is
// near full saturation, otherwise rounding to nearest will cause all values
// between 0xEC and 0xFE to always show as full saturation (0xFF).
return channel3Bits < 6
? Math.round(channel3Bits)
: (int) channel3Bits;
}
@SuppressWarnings("SameParameterValue")
private static String get9BitStyleIdentifier(int color24Bit) {
final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
}
/**
* injection point.
*/
@@ -135,36 +111,6 @@ public final class SeekbarColorPatch {
return original; // false = drawable style, true = lottie style.
}
/**
* Injection point.
* Old drawable style launch screen.
*/
public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
// Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
// without using any styles, but a color filter cannot selectively change the seekbar
// while keeping the red YT logo untouched.
// Even if the seekbar color xml value is changed to a completely different color (such as green),
// a color filter still cannot be selectively applied when the drawable has more than 1 color.
try {
// Must set the color even if custom seekbar is off,
// because the xml color was replaced with a themed value.
String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor);
Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
final int styleIdentifierDefault = Utils.getResourceIdentifierOrThrow(
seekbarStyle,
"style"
);
Resources.Theme theme = Utils.getContext().getResources().newTheme();
theme.applyStyle(styleIdentifierDefault, true);
vectorDrawable.applyTheme(theme);
} catch (Exception ex) {
Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
}
}
/**
* Injection point.
* Modern Lottie style animation.

View File

@@ -4,8 +4,10 @@ import android.app.Dialog;
import android.preference.PreferenceScreen;
import android.widget.Toolbar;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
import app.revanced.extension.youtube.settings.YouTubeActivityHook;
@@ -30,6 +32,17 @@ public class YouTubePreferenceFragment extends ToolbarPreferenceFragment {
preferenceScreen = getPreferenceScreen();
Utils.sortPreferenceGroups(preferenceScreen);
setPreferenceScreenToolbar(preferenceScreen);
// Clunky work around until preferences are custom classes that manage themselves.
// Custom branding only works with non-root install. But the preferences must be
// added during patched because of difficulties detecting during patching if it's
// a root install. So instead the non-functional preferences are removed during
// runtime if the app is mount (root) installation.
if (GmsCoreSupport.isPackageNameOriginal()) {
removePreferences(
BaseSettings.CUSTOM_BRANDING_ICON.key,
BaseSettings.CUSTOM_BRANDING_NAME.key);
}
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}

View File

@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
org.gradle.parallel = true
android.useAndroidX = true
kotlin.code.style = official
version = 5.43.0-dev.1
version = 5.44.0-dev.4

View File

@@ -184,6 +184,10 @@ public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatchKt {
public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatchKt {
public static final fun getSkipEnergyRechargeAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt {
public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@@ -481,7 +485,9 @@ public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatc
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
public static final fun is_7_16_or_greater ()Z
public static final fun is_7_33_or_greater ()Z
public static final fun is_8_05_or_greater ()Z
public static final fun is_8_10_or_greater ()Z
public static final fun is_8_11_or_greater ()Z
public static final fun is_8_15_or_greater ()Z
@@ -762,6 +768,14 @@ public final class app/revanced/patches/reddit/misc/tracking/url/SanitizeUrlQuer
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatchKt {
public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatchKt {
public static final fun getBypassDeviceChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View File

@@ -0,0 +1,182 @@
package app.revanced.patches.all.misc.customcertificates
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringsOption
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.getNode
import org.w3c.dom.Element
import java.io.File
val customNetworkSecurityPatch = resourcePatch(
name = "Custom network security",
description = "Allows trusting custom certificate authorities for a specific domain.",
use = false
) {
val targetDomains by stringsOption(
key = "targetDomains",
title = "Target domains",
description = "List of domains to which the custom trust configuration will be applied (one domain per entry).",
default = listOf("example.com"),
required = true
)
val includeSubdomains by booleanOption(
key = "includeSubdomains",
title = "Include subdomains",
description = "Applies the configuration to all subdomains of the target domains.",
default = false,
required = true
)
val customCAFilePaths by stringsOption(
key = "customCAFilePaths",
title = "Custom CA file paths",
description = """
List of paths to files in PEM or DER format (one file path per entry).
Makes an app trust the provided custom certificate authorities (CAs),
for the specified domains, and if the option "Include Subdomains" is enabled then also the subdomains.
CA files will be bundled in res/raw/ of resulting APK
""".trimIndentMultiline(),
default = null,
required = false
)
val allowUserCerts by booleanOption(
key = "allowUserCerts",
title = "Trust user added CAs",
description = "Makes an app trust certificates from the Android user store for the specified domains, and if the option \"Include Subdomains\" is enabled then also the subdomains.",
default = false,
required = true
)
val allowSystemCerts by booleanOption(
key = "allowSystemCerts",
title = "Trust system CAs",
description = "Makes an app trust certificates from the Android system store for the specified domains, and and if the option \"Include Subdomains\" is enabled then also the subdomains.",
default = true,
required = true
)
val allowCleartextTraffic by booleanOption(
key = "allowCleartextTraffic",
title = "Allow cleartext traffic (HTTP)",
description = "Allows unencrypted HTTP traffic for the specified domains, and if \"Include Subdomains\" is enabled then also the subdomains.",
default = false,
required = true
)
val overridePins by booleanOption(
key = "overridePins",
title = "Override certificate pinning",
description = "Overrides certificate pinning for the specified domains and their subdomains if the option \"Include Subdomains\" is enabled to allow inspecting app traffic via a proxy.",
default = false,
required = true
)
fun generateNetworkSecurityConfig(): String {
val targetDomains = targetDomains ?: emptyList()
val includeSubdomains = includeSubdomains ?: false
val customCAFilePaths = customCAFilePaths ?: emptyList()
val allowUserCerts = allowUserCerts ?: false
val allowSystemCerts = allowSystemCerts ?: true
val allowCleartextTraffic = allowCleartextTraffic ?: false
val overridePins = overridePins ?: false
val domainsXML = buildString {
targetDomains.forEach {
appendLine(""" <domain includeSubdomains="$includeSubdomains">$it</domain>""")
}
}.trimEnd()
val trustAnchorsXML = buildString {
if (allowSystemCerts) {
appendLine(""" <certificates src="system" overridePins="$overridePins" />""")
}
if (allowUserCerts) {
appendLine(""" <certificates src="user" overridePins="$overridePins" />""")
}
customCAFilePaths.forEach { path ->
val fileName = path.substringAfterLast('/').substringBeforeLast('.')
appendLine(""" <certificates src="@raw/$fileName" overridePins="$overridePins" />""")
}
}
if (trustAnchorsXML.isBlank()) {
throw PatchException("At least one trust anchor (System, User, or Custom CA) must be enabled.")
}
return """
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="$allowCleartextTraffic">
$domainsXML
<trust-anchors>
${trustAnchorsXML.trimEnd()}
</trust-anchors>
</domain-config>
</network-security-config>
""".trimIndent()
}
execute {
val nscFileNameBare = "network_security_config"
val resXmlDir = "res/xml"
val resRawDir = "res/raw"
val nscFileNameWithSuffix = "$nscFileNameBare.xml"
document("AndroidManifest.xml").use { document ->
val applicationNode = document.getNode("application") as Element
applicationNode.setAttribute("android:networkSecurityConfig", "@xml/$nscFileNameBare")
}
File(get(resXmlDir), nscFileNameWithSuffix).apply {
writeText(generateNetworkSecurityConfig())
}
for (customCAFilePath in customCAFilePaths ?: emptyList()) {
val file = File(customCAFilePath)
if (!file.exists()) {
throw PatchException(
"The custom CA file path cannot be found: " +
file.absolutePath
)
}
if (!file.isFile) {
throw PatchException(
"The custom CA file path must be a file: "
+ file.absolutePath
)
}
val caFileNameWithoutSuffix = customCAFilePath.substringAfterLast('/').substringBefore('.')
val caFile = File(customCAFilePath)
File(
get(resRawDir),
caFileNameWithoutSuffix
).writeText(
caFile.readText()
)
}
}
}

View File

@@ -1,26 +1,35 @@
package app.revanced.patches.duolingo.debug
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val enableDebugMenuPatch = bytecodePatch(
name = "Enable debug menu",
use = false,
use = false
) {
compatibleWith("com.duolingo"("5.158.4"))
compatibleWith("com.duolingo")
execute {
initializeBuildConfigProviderFingerprint.method.apply {
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
// It seems all categories are allowed on release. Force this on anyway.
debugCategoryAllowOnReleaseBuildsFingerprint.method.returnEarly(true)
addInstructions(
insertIndex,
"const/4 v$register, 0x1",
)
// Change build config debug build flag.
buildConfigProviderConstructorFingerprint.match(
buildConfigProviderToStringFingerprint.classDef
).let {
val index = it.patternMatch!!.startIndex
it.method.apply {
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"const/4 v$register, 0x1"
)
}
}
}
}

View File

@@ -4,16 +4,25 @@ import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* The `BuildConfigProvider` class has two booleans:
*
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
*/
internal val initializeBuildConfigProviderFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
returns("V")
opcodes(Opcode.IPUT_BOOLEAN)
strings("debug", "release", "china")
internal val debugCategoryAllowOnReleaseBuildsFingerprint = fingerprint {
returns("Z")
parameters()
custom { method, classDef ->
method.name == "getAllowOnReleaseBuilds" && classDef.type == "Lcom/duolingo/debug/DebugCategory;"
}
}
internal val buildConfigProviderConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters()
opcodes(Opcode.CONST_4)
}
internal val buildConfigProviderToStringFingerprint = fingerprint {
parameters()
returns("Ljava/lang/String;")
strings("BuildConfigProvider(") // Partial string match.
custom { method, _ ->
method.name == "toString"
}
}

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.duolingo.energy
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Matches the class found in [energyConfigToStringFingerprint].
*/
internal val initializeEnergyConfigFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
opcodes(Opcode.RETURN_VOID)
}
// Class name currently is not obfuscated but it may be in the future.
internal val energyConfigToStringFingerprint = fingerprint {
parameters()
returns("Ljava/lang/String;")
strings("EnergyConfig(", "maxEnergy=") // Partial string matches.
custom { method, _ -> method.name == "toString" }
}

View File

@@ -0,0 +1,31 @@
package app.revanced.patches.duolingo.energy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.findFieldFromToString
@Suppress("unused")
val skipEnergyRechargeAdsPatch = bytecodePatch(
name = "Skip energy recharge ads",
description = "Skips watching ads to recharge energy."
) {
compatibleWith("com.duolingo")
execute {
initializeEnergyConfigFingerprint
.match(energyConfigToStringFingerprint.classDef)
.method.apply {
val energyField = energyConfigToStringFingerprint.method
.findFieldFromToString("energy=")
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
addInstructions(
insertIndex,
"""
const/16 v0, 99
iput v0, p0, $energyField
"""
)
}
}
}

View File

@@ -47,6 +47,7 @@ val spoofFeaturesPatch = bytecodePatch(
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
),
title = "Features to disable",
description = "Google Pixel exclusive features to disable." +

View File

@@ -61,7 +61,7 @@ val customBrandingPatch = baseCustomBrandingPatch(
originalLauncherIconName = "ic_launcher_release",
originalAppName = "@string/app_launcher_name",
originalAppPackageName = MUSIC_PACKAGE_NAME,
copyExistingIntentsToAliases = false,
isYouTubeMusic = true,
numberOfPresetAppNames = 5,
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,

View File

@@ -6,6 +6,7 @@ import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_7_16_or_greater
import app.revanced.patches.music.playservice.is_7_33_or_greater
import app.revanced.patches.music.playservice.is_8_11_or_greater
import app.revanced.patches.music.playservice.is_8_15_or_greater
@@ -18,7 +19,7 @@ import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
fixMediaFetchHotConfig = { true },
fixMediaFetchHotConfig = { is_7_16_or_greater },
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },

View File

@@ -3,14 +3,11 @@ package app.revanced.patches.music.misc.tracks
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_8_10_or_greater
import app.revanced.patches.music.playservice.is_8_05_or_greater
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
@Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch(
block = {
@@ -27,8 +24,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
)
)
},
fixUseLocalizedAudioTrackFlag = is_8_10_or_greater,
fixUseLocalizedAudioTrackFlag = { is_8_05_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
subclassExtensionClassDescriptor = "Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.MISC,
)

View File

@@ -4,14 +4,21 @@ package app.revanced.patches.music.playservice
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.findPlayStoreServicesVersion
import kotlin.properties.Delegates
var is_7_33_or_greater = false
// Use notNull delegate so an exception is thrown if these fields are accessed before they are set.
var is_7_16_or_greater: Boolean by Delegates.notNull()
private set
var is_8_10_or_greater = false
var is_7_33_or_greater: Boolean by Delegates.notNull()
private set
var is_8_11_or_greater = false
var is_8_05_or_greater: Boolean by Delegates.notNull()
private set
var is_8_15_or_greater = false
var is_8_10_or_greater: Boolean by Delegates.notNull()
private set
var is_8_11_or_greater: Boolean by Delegates.notNull()
private set
var is_8_15_or_greater: Boolean by Delegates.notNull()
private set
val versionCheckPatch = resourcePatch(
@@ -23,8 +30,10 @@ val versionCheckPatch = resourcePatch(
val playStoreServicesVersion = findPlayStoreServicesVersion()
// All bug fix releases always seem to use the same play store version as the minor version.
is_7_16_or_greater = 243499000 <= playStoreServicesVersion
is_7_33_or_greater = 245199000 <= playStoreServicesVersion
is_8_10_or_greater = 244799000 <= playStoreServicesVersion
is_8_05_or_greater = 250599000 <= playStoreServicesVersion
is_8_10_or_greater = 251099000 <= playStoreServicesVersion
is_8_11_or_greater = 251199000 <= playStoreServicesVersion
is_8_15_or_greater = 251530000 <= playStoreServicesVersion
}

View File

@@ -0,0 +1,34 @@
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.asSequence
import org.w3c.dom.Element
@Suppress("unused")
internal val addManifestPermissionsPatch = resourcePatch {
val requiredPermissions = listOf(
"android.permission.READ_PHONE_STATE",
"android.permission.FOREGROUND_SERVICE_MICROPHONE",
"android.permission.RECORD_AUDIO",
)
execute {
document("AndroidManifest.xml").use { document ->
document.getElementsByTagName("manifest").item(0).let { manifestEl ->
// Check which permissions are missing
val existingPermissionNames = document.getElementsByTagName("uses-permission").asSequence()
.mapNotNull { (it as? Element)?.getAttribute("android:name") }.toSet()
val missingPermissions = requiredPermissions.filterNot { it in existingPermissionNames }
// Then add them
for (permission in missingPermissions) {
val element = document.createElement("uses-permission")
element.setAttribute("android:name", permission)
manifestEl.appendChild(element)
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
@file:Suppress("unused")
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.fingerprint
import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.fromMethodReference
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val permissionRequestListFingerprint = fingerprint {
strings(
"android.permission.POST_NOTIFICATIONS",
"android.permission.READ_MEDIA_AUDIO",
"android.permission.RECORD_AUDIO"
)
custom { method, _ -> method.name == "<clinit>" }
}

View File

@@ -0,0 +1,42 @@
@file:Suppress("unused")
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.samsung.radio.restrictions.device.bypassDeviceChecksPatch
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch;"
val fixCrashPatch = bytecodePatch(
name = "Fix crashes", description = "Prevents the app from crashing because of missing system permissions."
) {
dependsOn(addManifestPermissionsPatch, bypassDeviceChecksPatch)
extendWith("extensions/samsung/radio.rve")
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
execute {
permissionRequestListFingerprint.method.apply {
findInstructionIndicesReversedOrThrow(Opcode.FILLED_NEW_ARRAY).forEach { filledNewArrayIndex ->
val moveResultIndex = indexOfFirstInstruction(filledNewArrayIndex, Opcode.MOVE_RESULT_OBJECT)
if (moveResultIndex < 0) return@forEach // No move-result-object found after the filled-new-array
// Get the register where the array is saved
val arrayRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
// Invoke the method from the extension
addInstructions(
moveResultIndex + 1, """
invoke-static { v$arrayRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->fixPermissionRequestList([Ljava/lang/String;)[Ljava/lang/String;
move-result-object v$arrayRegister
"""
)
}
}
}
}

View File

@@ -0,0 +1,55 @@
package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.StringReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch;"
@Suppress("unused")
val bypassDeviceChecksPatch = bytecodePatch(
name = "Bypass device checks",
description = "Removes firmware and region blacklisting. " +
"This patch will still not allow the app to run on devices that do not have the required hardware.",
) {
extendWith("extensions/samsung/radio.rve")
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
execute {
// Return false = The device is not blacklisted
checkDeviceFingerprint.method.apply {
// Find the first string that start with "SM-", that's the list of incompatible devices
val firstStringIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.startsWith("SM-") == true
}
// Find the following filled-new-array (or filled-new-array/range) instruction
val filledNewArrayIndex = indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
}
// Find an available register for our use
val resultRegister = findFreeRegister(filledNewArrayIndex + 1)
// Store the array there and invoke the method that we added to the class earlier
addInstructions(
filledNewArrayIndex + 1, """
move-result-object v$resultRegister
invoke-static { v$resultRegister }, $EXTENSION_CLASS_DESCRIPTOR->checkIfDeviceIsIncompatible([Ljava/lang/String;)Z
move-result v$resultRegister
return v$resultRegister
"""
)
// Remove the instructions before our strings
removeInstructions(0, firstStringIndex)
}
}
}

View File

@@ -0,0 +1,61 @@
package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.fingerprint
import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.fromMethodReference
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val checkDeviceFingerprint = fingerprint {
returns("Z")
custom { method, _ ->
/* Check for methods call to:
- Landroid/os/SemSystemProperties;->getSalesCode()Ljava/lang/String;
- Landroid/os/SemSystemProperties;->getCountryIso()Ljava/lang/String;
*/
val impl = method.implementation ?: return@custom false
// Track which target methods we've found
val foundMethods = mutableSetOf<MethodCall>()
// Scan method instructions for calls to our target methods
for (instr in impl.instructions) {
val ref = instr.getReference<MethodReference>() ?: continue
val mc = fromMethodReference<MethodCall>(ref) ?: continue
if (mc == MethodCall.GetSalesCode || mc == MethodCall.GetCountryIso) {
foundMethods.add(mc)
// If we found both methods, return success
if (foundMethods.size == 2) {
return@custom true
}
}
}
// Only match if both methods are present
return@custom false
}
}
// Information about method calls we want to replace
private enum class MethodCall(
override val definedClassName: String,
override val methodName: String,
override val methodParams: Array<String>,
override val returnType: String,
) : IMethodCall {
GetSalesCode(
"Landroid/os/SemSystemProperties;",
"getSalesCode",
arrayOf(),
"Ljava/lang/String;",
),
GetCountryIso(
"Landroid/os/SemSystemProperties;",
"getCountryIso",
arrayOf(),
"Ljava/lang/String;",
),
}

View File

@@ -2,6 +2,7 @@ package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.ResourcePatchBuilder
@@ -12,14 +13,24 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.copyResources
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.removeFromParent
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import org.w3c.dom.Element
import org.w3c.dom.NodeList
import java.io.File
@@ -47,13 +58,15 @@ private const val LAUNCHER_RESOURCE_NAME_PREFIX = "revanced_launcher_"
private const val LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX = "revanced_adaptive_background_"
private const val LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX = "revanced_adaptive_foreground_"
private const val LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX = "revanced_adaptive_monochrome_"
private const val NOTIFICATION_ICON_NAME = "revanced_notification_icon"
private val USER_CUSTOM_ADAPTIVE_FILE_NAMES = arrayOf(
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png"
)
private const val USER_CUSTOM_MONOCHROME_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
private const val USER_CUSTOM_MONOCHROME_FILE_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
private const val USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME = "${NOTIFICATION_ICON_NAME}_$CUSTOM_USER_ICON_STYLE_NAME.xml"
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/patches/CustomBrandingPatch;"
@@ -65,7 +78,7 @@ internal fun baseCustomBrandingPatch(
originalLauncherIconName: String,
originalAppName: String,
originalAppPackageName: String,
copyExistingIntentsToAliases: Boolean,
isYouTubeMusic: Boolean,
numberOfPresetAppNames: Int,
mainActivityOnCreateFingerprint: Fingerprint,
mainActivityName: String,
@@ -96,8 +109,9 @@ internal fun baseCustomBrandingPatch(
Each of the folders must contain all of the following files:
${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")}
Optionally, the path can contain a 'drawable' folder with the monochrome icon file:
$USER_CUSTOM_MONOCHROME_NAME
Optionally, the path contains a 'drawable' folder with any of the monochrome icon files:
$USER_CUSTOM_MONOCHROME_FILE_NAME
$USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
""".trimIndentMultiline()
)
@@ -105,7 +119,7 @@ internal fun baseCustomBrandingPatch(
dependsOn(
addResourcesPatch,
resourceMappingPatch,
bytecodePatch {
execute {
mainActivityOnCreateFingerprint.method.addInstruction(
@@ -114,25 +128,68 @@ internal fun baseCustomBrandingPatch(
)
numberOfPresetAppNamesExtensionFingerprint.method.returnEarly(numberOfPresetAppNames)
notificationFingerprint.method.apply {
val getBuilderIndex = if (isYouTubeMusic) {
// YT Music the field is not a plain object type.
indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "Landroid/app/Notification\$Builder;"
}
} else {
// Find the field name of the notification builder. Field is an Object type.
val builderCastIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST &&
reference?.type == "Landroid/app/Notification\$Builder;"
}
indexOfFirstInstructionReversedOrThrow(builderCastIndex) {
getReference<FieldReference>()?.type == "Ljava/lang/Object;"
}
}
val builderFieldName = getInstruction<ReferenceInstruction>(getBuilderIndex)
.getReference<FieldReference>()
findInstructionIndicesReversedOrThrow(
Opcode.RETURN_VOID
).forEach { index ->
addInstructionsAtControlFlowLabel(
index,
"""
move-object/from16 v0, p0
iget-object v0, v0, $builderFieldName
check-cast v0, Landroid/app/Notification${'$'}Builder;
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V
"""
)
}
}
}
}
},
)
finalize {
val useCustomName = customName != null
val useCustomIcon = customIcon != null
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) {
if (useCustomName || useCustomIcon) {
// Can only check if app is root installation by checking if change package name patch is in use.
// and can only do that in the finalize block here.
// The UI preferences cannot be selectively added here, because the settings finalize block
// may have already run and the settings are already wrote to file.
// Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes),
// and the non-functional in-app settings are removed on app startup by extension code.
if (customName != null || customIcon != null) {
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) {
Logger.getLogger(this::class.java.name).warning(
"Custom branding does not work with root installation. No changes applied."
)
}
return@finalize
}
}
execute {
addResources("shared", "layout.branding.baseCustomBrandingPatch")
addResources(addResourcePatchName, "layout.branding.customBrandingPatch")
preferenceScreen.addPreferences(
if (useCustomName) {
if (customName != null ) {
ListPreference(
key = "revanced_custom_branding_name",
entriesKey = "revanced_custom_branding_name_custom_entries",
@@ -141,7 +198,7 @@ internal fun baseCustomBrandingPatch(
} else {
ListPreference("revanced_custom_branding_name")
},
if (useCustomIcon) {
if (customIcon != null) {
ListPreference(
key = "revanced_custom_branding_icon",
entriesKey = "revanced_custom_branding_icon_custom_entries",
@@ -151,11 +208,6 @@ internal fun baseCustomBrandingPatch(
ListPreference("revanced_custom_branding_icon")
}
)
}
execute {
addResources("shared", "layout.branding.baseCustomBrandingPatch")
addResources(addResourcePatchName, "layout.branding.customBrandingPatch")
val useCustomName = customName != null
val useCustomIcon = customIcon != null
@@ -167,7 +219,7 @@ internal fun baseCustomBrandingPatch(
"drawable",
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$style.xml",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$style.xml",
"$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$style.xml"
"$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$style.xml",
),
ResourceGroup(
"mipmap-anydpi",
@@ -176,20 +228,27 @@ internal fun baseCustomBrandingPatch(
)
}
// Copy template user icon, because the aliases must be added even if no user icon is provided.
copyResources(
"custom-branding",
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml",
),
// Push notification 'small' icon.
ResourceGroup(
"drawable",
"$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml",
"$NOTIFICATION_ICON_NAME.xml"
),
// Copy template user icon, because the aliases must be added even if no user icon is provided.
ResourceGroup(
"drawable",
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
),
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
)
)
// Copy template icon png files.
// Copy template icon files.
mipmapDirectories.forEach { dpi ->
copyResources(
"custom-branding",
@@ -232,13 +291,7 @@ internal fun baseCustomBrandingPatch(
alias.setAttribute("android:targetActivity", mainActivityName)
// Copy all intents from the original alias so long press actions still work.
if (copyExistingIntentsToAliases) {
for (i in 0 until intents.length) {
alias.appendChild(
intents.item(i).cloneNode(true)
)
}
} else {
if (isYouTubeMusic) {
val intentFilter = document.createElement("intent-filter").apply {
val action = document.createElement("action")
action.setAttribute("android:name", "android.intent.action.MAIN")
@@ -249,6 +302,12 @@ internal fun baseCustomBrandingPatch(
appendChild(category)
}
alias.appendChild(intentFilter)
} else {
for (i in 0 until intents.length) {
alias.appendChild(
intents.item(i).cloneNode(true)
)
}
}
return alias
@@ -375,15 +434,20 @@ internal fun baseCustomBrandingPatch(
}
}
// Copy monochrome if it provided.
val monochromeRelativePath = "drawable/$USER_CUSTOM_MONOCHROME_NAME"
val monochromeFile = iconPathFile.resolve(monochromeRelativePath)
if (monochromeFile.exists()) {
monochromeFile.copyTo(
target = resourceDirectory.resolve(monochromeRelativePath),
overwrite = true
)
copiedFiles = true
// Copy monochrome and small notification icon if it provided.
arrayOf(
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
).forEach { fileName ->
val relativePath = "drawable/$fileName"
val file = iconPathFile.resolve(relativePath)
if (file.exists()) {
file.copyTo(
target = resourceDirectory.resolve(relativePath),
overwrite = true
)
copiedFiles = true
}
}
if (!copiedFiles) {

View File

@@ -11,3 +11,11 @@ internal val numberOfPresetAppNamesExtensionFingerprint = fingerprint {
method.name == "numberOfPresetAppNames" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}
// A much simpler fingerprint exists that can set the small icon (contains string "414843287017"),
// but that has limited usage and this fingerprint allows changing any part of the notification.
internal val notificationFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("L")
strings("key_action_priority")
}

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
internal val formatStreamModelToStringFingerprint = fingerprint {
@@ -20,11 +20,7 @@ internal val formatStreamModelToStringFingerprint = fingerprint {
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
internal val selectAudioStreamFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("L")
custom { method, _ ->
method.parameters.size > 2 // Method has a large number of parameters and may change.
&& method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG)
literal {
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG
}
}

View File

@@ -34,7 +34,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
internal fun forceOriginalAudioPatch(
block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {},
fixUseLocalizedAudioTrackFlag: Boolean,
fixUseLocalizedAudioTrackFlag: BytecodePatchContext.() -> Boolean,
mainActivityOnCreateFingerprint: Fingerprint,
subclassExtensionClassDescriptor: String,
preferenceScreen: BasePreferenceScreen.Screen
@@ -64,7 +64,7 @@ internal fun forceOriginalAudioPatch(
// Disable feature flag that ignores the default track flag
// and instead overrides to the user region language.
if (fixUseLocalizedAudioTrackFlag) {
if (fixUseLocalizedAudioTrackFlag()) {
selectAudioStreamFingerprint.method.insertLiteralOverride(
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->ignoreDefaultAudioStream(Z)Z"

View File

@@ -47,11 +47,15 @@ val changeLyricsProviderPatch = bytecodePatch(
// may not allow network connections or the network may be down.
try {
InetAddress.getByName(host)
} catch (e: UnknownHostException) {
} catch (_: UnknownHostException) {
Logger.getLogger(this::class.java.name).warning(
"Host \"$host\" did not resolve to any domain."
)
} catch (_: Exception) {
// Must ignore any kind of exception. Trying to resolve network
// on Manager throws android.os.NetworkOnMainThreadException
}
true
}

View File

@@ -1,23 +1,26 @@
package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import java.net.InetAddress
import java.net.UnknownHostException
import java.util.logging.Logger
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
internal val domainNameOption by stringOption(
internal val domainNameOption = stringOption(
key = "domainName",
default = "https://fxtwitter.com",
default = "fxtwitter.com",
title = "Domain name",
description = "The domain name to use when sharing links.",
required = true,
@@ -28,23 +31,25 @@ internal val domainNameOption by stringOption(
// may not allow network connections or the network may be down.
try {
InetAddress.getByName(it)
} catch (e: UnknownHostException) {
} catch (_: UnknownHostException) {
Logger.getLogger(this::class.java.name).warning(
"Host \"$it\" did not resolve to any domain."
)
} catch (_: Exception) {
// Must ignore any kind of exception. Trying to resolve network
// on Manager throws android.os.NetworkOnMainThreadException
}
true
}
// TODO restore this once Manager uses a fixed version of Patcher
/*
internal val changeLinkSharingDomainResourcePatch = resourcePatch {
execute {
val domainName = domainNameOption!!
val domainName = domainNameOption.value!!
val shareLinkTemplate = if (domainName.endsWith("/")) {
"$domainName%1\$s/status/%2\$s"
} else {
"$domainName/%1\$s/status/%2\$s"
}
val shareLinkTemplate = "https://$domainName/%1\$s/status/%2\$s"
document("res/values/strings.xml").use { document ->
document.documentElement.childNodes.findElementByAttributeValueOrThrow(
@@ -54,14 +59,15 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
}
}
}
*/
@Suppress("unused")
val changeLinkSharingDomainPatch = bytecodePatch(
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
description = "$PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN Including this patch can prevent making posts that quote other posts.",
use = false
) {
dependsOn(
changeLinkSharingDomainResourcePatch,
sharedExtensionPatch,
)
@@ -72,11 +78,11 @@ val changeLinkSharingDomainPatch = bytecodePatch(
)
)
execute {
val domainName = domainNameOption!!
val domainName by domainNameOption()
execute {
// Replace the domain name in the link sharing extension methods.
linkSharingDomainHelperFingerprint.method.returnEarly(domainName)
linkSharingDomainHelperFingerprint.method.returnEarly(domainName!!)
// Replace the domain name when copying a link with "Copy link" button.
linkBuilderFingerprint.method.addInstructions(
@@ -87,5 +93,22 @@ val changeLinkSharingDomainPatch = bytecodePatch(
return-object p0
"""
)
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Replace the domain name in the "Share via..." dialog.
linkResourceGetterFingerprint.method.apply {
val templateIdConstIndex = indexOfFirstInstructionOrThrow(Opcode.CONST)
// Format the link with the new domain name register (1 instruction below the const).
val formatLinkCallIndex = templateIdConstIndex + 1
val register = getInstruction<FiveRegisterInstruction>(formatLinkCallIndex).registerE
// Replace the original method call with the new method call.
replaceInstruction(
formatLinkCallIndex,
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
"formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;",
)
}
}
}

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal val openLinkFingerprint = fingerprint {
returns("V")
@@ -17,6 +18,18 @@ internal val linkBuilderFingerprint = fingerprint {
strings("/%1\$s/status/%2\$d")
}
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Returns a shareable link for the "Share via..." dialog.
internal val linkResourceGetterFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Landroid/content/res/Resources;")
custom { _, classDef ->
classDef.fields.any { field ->
field.type.startsWith("Lcom/twitter/model/core/")
}
}
}
internal val linkSharingDomainHelperFingerprint = fingerprint {
custom { method, classDef ->
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR

View File

@@ -13,7 +13,7 @@ val customBrandingPatch = baseCustomBrandingPatch(
originalLauncherIconName = "ic_launcher",
originalAppName = "@string/application_name",
originalAppPackageName = YOUTUBE_PACKAGE_NAME,
copyExistingIntentsToAliases = true,
isYouTubeMusic = false,
numberOfPresetAppNames = 5,
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
mainActivityName = YOUTUBE_MAIN_ACTIVITY_NAME,

View File

@@ -1,11 +1,9 @@
package app.revanced.patches.youtube.layout.seekbar
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
@@ -17,17 +15,13 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertLiteralOverride
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -38,9 +32,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import org.w3c.dom.Element
import java.io.ByteArrayInputStream
import kotlin.use
internal var reelTimeBarPlayedColorId = -1L
private set
@@ -57,8 +48,6 @@ internal var ytTextSecondaryId = -1L
internal var inlineTimeBarLiveSeekableRangeId = -1L
private set
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
private val seekbarColorResourcePatch = resourcePatch {
dependsOn(
settingsPatch,
@@ -92,21 +81,6 @@ private val seekbarColorResourcePatch = resourcePatch {
"inline_time_bar_live_seekable_range"
]
// Modify the resume playback drawable and replace the progress bar with a custom drawable.
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
val layerList = document.getElementsByTagName("layer-list").item(0) as Element
val progressNode = layerList.getElementsByTagName("item").item(1) as Element
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
throw PatchException("Could not find progress bar")
}
val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element
val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element
val replacementNode = document.createElement(
"app.revanced.extension.youtube.patches.theme.ProgressBarDrawable",
)
scaleNode.replaceChild(replacementNode, shapeNode)
}
ytYoutubeMagentaColorId = resourceMappings[
"color",
"yt_youtube_magenta",
@@ -115,99 +89,9 @@ private val seekbarColorResourcePatch = resourcePatch {
"attr",
"ytStaticBrandRed",
]
// Add attribute and styles for splash screen custom color.
// Using a style is the only way to selectively change just the seekbar fill color.
//
// Because the style colors must be hard coded for all color possibilities,
// instead of allowing 24 bit color the style is restricted to 9-bit (3 bits per color channel)
// and the style color closest to the users custom color is used for the splash screen.
arrayOf(
inputStreamFromBundledResource("seekbar/values", "attrs.xml")!! to "res/values/attrs.xml",
ByteArrayInputStream(create9BitSeekbarColorStyles().toByteArray()) to "res/values/styles.xml"
).forEach { (source, destination) ->
"resources".copyXmlNode(
document(source),
document(destination),
).close()
}
fun setSplashDrawablePathFillColor(xmlFileNames: Iterable<String>, vararg resourceNames: String) {
xmlFileNames.forEach { xmlFileName ->
document(xmlFileName).use { document ->
val childNodes = document.childNodes
resourceNames.forEach { elementId ->
val element = childNodes.findElementByAttributeValueOrThrow(
"android:name",
elementId
)
val attribute = "android:fillColor"
if (!element.hasAttribute(attribute)) {
throw PatchException("Could not find $attribute for $elementId")
}
element.setAttribute(attribute, "?attr/$splashSeekbarColorAttributeName")
}
}
}
}
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$startup_animation_light__0.xml",
"res/drawable/\$startup_animation_dark__0.xml"
),
"_R_G_L_10_G_D_0_P_0"
)
if (!is_19_46_or_greater) {
// Resources removed in 19.46+
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$buenos_aires_animation_light__0.xml",
"res/drawable/\$buenos_aires_animation_dark__0.xml"
),
"_R_G_L_8_G_D_0_P_0"
)
}
}
}
/**
* Generate a style xml with all combinations of 9-bit colors.
*/
private fun create9BitSeekbarColorStyles(): String = StringBuilder().apply {
append("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
append("<resources>\n")
for (red in 0..7) {
for (green in 0..7) {
for (blue in 0..7) {
val name = "${red}_${green}_${blue}"
fun roundTo3BitHex(channel8Bits: Int) =
(channel8Bits * 255 / 7).toString(16).padStart(2, '0')
val r = roundTo3BitHex(red)
val g = roundTo3BitHex(green)
val b = roundTo3BitHex(blue)
val color = "#ff$r$g$b"
append(
"""
<style name="splash_seekbar_color_style_$name">
<item name="$splashSeekbarColorAttributeName">$color</item>
</style>
"""
)
}
}
}
append("</resources>")
}.toString()
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;"
val seekbarColorPatch = bytecodePatch(
@@ -344,21 +228,6 @@ val seekbarColorPatch = bytecodePatch(
// Hook the splash animation to set the a seekbar color.
mainActivityOnCreateFingerprint.method.apply {
val drawableIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/widget/ImageView;"
&& reference.name == "getDrawable"
}
val checkCastIndex = indexOfFirstInstructionOrThrow(drawableIndex, Opcode.CHECK_CAST)
val drawableRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$drawableRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setSplashAnimationDrawableTheme(Landroid/graphics/drawable/AnimatedVectorDrawable;)V"
)
// Replace the Lottie animation view setAnimation(int) call.
val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name
findInstructionIndicesReversedOrThrow {
@@ -371,13 +240,11 @@ val seekbarColorPatch = bytecodePatch(
replaceInstruction(
index,
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" +
"(Lcom/airbnb/lottie/LottieAnimationView;I)V"
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie(Lcom/airbnb/lottie/LottieAnimationView;I)V"
)
}
}
// Add non obfuscated method aliases for `setAnimation(int)`
// and `setAnimation(InputStream, String)` so extension code can call them.
lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply {

View File

@@ -4,72 +4,75 @@ package app.revanced.patches.youtube.misc.playservice
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.findPlayStoreServicesVersion
import kotlin.properties.Delegates
// Use notNull delegate so an exception is thrown if these fields are accessed before they are set.
@Deprecated("19.34.42 is the lowest supported version")
var is_19_03_or_greater = false
var is_19_03_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_04_or_greater = false
var is_19_04_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_16_or_greater = false
var is_19_16_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_17_or_greater = false
var is_19_17_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_18_or_greater = false
var is_19_18_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_23_or_greater = false
var is_19_23_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_25_or_greater = false
var is_19_25_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_26_or_greater = false
var is_19_26_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_29_or_greater = false
var is_19_29_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_32_or_greater = false
var is_19_32_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_33_or_greater = false
var is_19_33_or_greater : Boolean by Delegates.notNull()
private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_34_or_greater = false
var is_19_34_or_greater : Boolean by Delegates.notNull()
private set
var is_19_35_or_greater = false
var is_19_35_or_greater : Boolean by Delegates.notNull()
private set
var is_19_36_or_greater = false
var is_19_36_or_greater : Boolean by Delegates.notNull()
private set
var is_19_41_or_greater = false
var is_19_41_or_greater : Boolean by Delegates.notNull()
private set
var is_19_43_or_greater = false
var is_19_43_or_greater : Boolean by Delegates.notNull()
private set
var is_19_46_or_greater = false
var is_19_46_or_greater : Boolean by Delegates.notNull()
private set
var is_19_47_or_greater = false
var is_19_47_or_greater : Boolean by Delegates.notNull()
private set
var is_19_49_or_greater = false
var is_19_49_or_greater : Boolean by Delegates.notNull()
private set
var is_20_02_or_greater = false
var is_20_02_or_greater : Boolean by Delegates.notNull()
private set
var is_20_03_or_greater = false
var is_20_03_or_greater : Boolean by Delegates.notNull()
private set
var is_20_05_or_greater = false
var is_20_05_or_greater : Boolean by Delegates.notNull()
private set
var is_20_07_or_greater = false
var is_20_07_or_greater : Boolean by Delegates.notNull()
private set
var is_20_09_or_greater = false
var is_20_09_or_greater : Boolean by Delegates.notNull()
private set
var is_20_10_or_greater = false
var is_20_10_or_greater : Boolean by Delegates.notNull()
private set
var is_20_14_or_greater = false
var is_20_14_or_greater : Boolean by Delegates.notNull()
private set
var is_20_15_or_greater = false
var is_20_15_or_greater : Boolean by Delegates.notNull()
private set
val versionCheckPatch = resourcePatch(

View File

@@ -8,9 +8,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;"
@Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch(
block = {
@@ -29,8 +26,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
)
)
},
fixUseLocalizedAudioTrackFlag = is_20_07_or_greater,
fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.VIDEO,
)

View File

@@ -218,9 +218,9 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
<string name="revanced_hide_community_posts_title">İcma elanların gizlət</string>
<string name="revanced_hide_community_posts_summary_on">İcma elanları gizlədilib</string>
<string name="revanced_hide_community_posts_summary_off">İcma elanları göstərilir</string>
<string name="revanced_hide_compact_banner_title">Yığcam etiketləri gizlət</string>
<string name="revanced_hide_compact_banner_summary_on">Yığcam etiketlər gizlidir</string>
<string name="revanced_hide_compact_banner_summary_off">Yığcam etiketlər göstərilir</string>
<string name="revanced_hide_compact_banner_title">Yığcam afişaları gizlət</string>
<string name="revanced_hide_compact_banner_summary_on">Yığcam afişalar gizlidir</string>
<string name="revanced_hide_compact_banner_summary_off">Yığcam afişalar görünür</string>
<string name="revanced_hide_crowdfunding_box_title">İanə qutusunu gizlət</string>
<string name="revanced_hide_crowdfunding_box_summary_on">İanə qutusu gizlidir</string>
<string name="revanced_hide_crowdfunding_box_summary_off">İanə qutusu göstərilir</string>
@@ -471,9 +471,9 @@ Məhdudiyyətlər
<string name="revanced_hide_creator_store_shelf_title">Yaradıcı mağaza bölümün gizlət</string>
<string name="revanced_hide_creator_store_shelf_summary_on">Yaradıcı alış-veriş cərgəsi video oynadıcı altında gizlidir</string>
<string name="revanced_hide_creator_store_shelf_summary_off">Yaradıcı alış-veriş cərgəsi video oynadıcı altında görünür</string>
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza etiketini gizlət</string>
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran alış-veriş etiketi gizlədilib</string>
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran alış-veriş etiketi görünür</string>
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza afişasın gizlət</string>
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran mağaza afişası gizlidir</string>
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran mağaza afişası görünür</string>
<string name="revanced_hide_fullscreen_ads_title">Tam ekran reklamlarını gizlət</string>
<string name="revanced_hide_fullscreen_ads_summary_on">"Tam ekran reklamları gizlidir
@@ -484,9 +484,9 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
<string name="revanced_hide_general_ads_title">Ümumi reklamları gizlət</string>
<string name="revanced_hide_general_ads_summary_on">Ümumi reklamlar gizlidir</string>
<string name="revanced_hide_general_ads_summary_off">Ümumi reklamlar göstərilir</string>
<string name="revanced_hide_merchandise_banners_title">Məhsul etiketlərini gizlət</string>
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul etiketləri gizlədilir</string>
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul etiketləri göstərilir</string>
<string name="revanced_hide_merchandise_banners_title">Məhsul afişaların gizlət</string>
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul afişaları gizlədilir</string>
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul afişaları görünür</string>
<string name="revanced_hide_paid_promotion_label_title">Ödənişli tanıtım etiketini gizlət</string>
<string name="revanced_hide_paid_promotion_label_summary_on">Ödənişli reklam etiketi gizlədilib</string>
<string name="revanced_hide_paid_promotion_label_summary_off">Ödənişli reklam etiketi göstərilir</string>
@@ -496,7 +496,7 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
<string name="revanced_hide_shopping_links_title">Alış-veriş linklərini gizlət</string>
<string name="revanced_hide_shopping_links_summary_on">Alış-veriş linkləri video təsvirdə gizlidir</string>
<string name="revanced_hide_shopping_links_summary_off">Alış-veriş linkləri video təsvirdə görünür</string>
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” panelin gizlət</string>
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” afişasın gizlət</string>
<string name="revanced_hide_view_products_banner_summary_on">Məhsullara baxış etiketi video örtüyündə gizlidir</string>
<string name="revanced_hide_view_products_banner_summary_off">Məhsullara baxış etiketi video örtüyündə görünür</string>
<string name="revanced_hide_web_search_results_title">Veb axtarış nəticələrini gizlət</string>

View File

@@ -1158,13 +1158,13 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_segments_highlight_sum">Se osa videota, jota useimmat ihmiset etsivät</string>
<string name="revanced_sb_segments_intro">Tauko/Introanimaatio</string>
<string name="revanced_sb_segments_intro_sum">Aikaväli ilman varsinaista sisältöä. Voi olla tauko, staattinen kehys tai toistuva animaatio. Ei sisällä siirtymiä, jotka sisältävät tietoa</string>
<string name="revanced_sb_segments_outro">Loppukortit / Tekijätiedot</string>
<string name="revanced_sb_segments_outro">Loppukortit / -tekstit</string>
<string name="revanced_sb_segments_outro_sum">Lopputekstit tai kun YouTuben loppukortit tulevat näkyviin. Ei lopetuksille, joissa on tietoa</string>
<string name="revanced_sb_segments_hook">Koukku / Tervehdykset</string>
<string name="revanced_sb_segments_hook_sum">Kertovat trailerit tulevasta videosta, tervehdykset ja hyvästelyt. Ei sisällä osioita, jotka lisäävät lisäsisältöä</string>
<string name="revanced_sb_segments_preview">Esikatselu / Yhteenveto</string>
<string name="revanced_sb_segments_preview">Esikatselu / Kertaus</string>
<string name="revanced_sb_segments_preview_sum">Kokoelma leikkeitä, jotka osoittavat, mitä on tulossa tai mitä tapahtui videossa tai muissa sarjan videoissa, joiden kaikki informaatio toistuu muualla</string>
<string name="revanced_sb_segments_filler">Tangentti / Vitsit</string>
<string name="revanced_sb_segments_filler">Toissijaiset kohtaukset / Vitsit</string>
<string name="revanced_sb_segments_filler_sum">Epäolennaiset kohtaukset tai vitsit, joita ei tarvita videon pääsisällön ymmärtämiseen. Ei sisällä osioita, jotka tarjoavat kontekstia tai taustatietoja</string>
<string name="revanced_sb_segments_nomusic">Musiikki: Musiikiton osa</string>
<string name="revanced_sb_segments_nomusic_sum">Vain musiikkivideoille. Musiikkivideoiden osiot ilman musiikkia, jotka eivät jo kuulu toiseen kategoriaan</string>
@@ -1182,7 +1182,7 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_skip_button_preview_beginning">Ohita esikatselu</string>
<string name="revanced_sb_skip_button_preview_middle">Ohita esikatselu</string>
<string name="revanced_sb_skip_button_preview_end">Ohita kertaus</string>
<string name="revanced_sb_skip_button_filler">Ohita Tangentti</string>
<string name="revanced_sb_skip_button_filler">Ohita toissijainen kohtaus</string>
<string name="revanced_sb_skip_button_nomusic">Ohita musiikiton</string>
<string name="revanced_sb_skip_button_unsubmitted">Ohita osio</string>
<string name="revanced_sb_skipped_sponsor">Sponsori ohitettiin</string>
@@ -1193,11 +1193,11 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_skipped_intro_middle">Tauko ohitettiin</string>
<string name="revanced_sb_skipped_intro_end">Tauko ohitettiin</string>
<string name="revanced_sb_skipped_outro">Outro ohitettiin</string>
<string name="revanced_sb_skipped_hook">Ohitettu koukku</string>
<string name="revanced_sb_skipped_hook">Koukku ohitettiin</string>
<string name="revanced_sb_skipped_preview_beginning">Esikatselu ohitettiin</string>
<string name="revanced_sb_skipped_preview_middle">Esikatselu ohitettiin</string>
<string name="revanced_sb_skipped_preview_end">Kertaus ohitettiin</string>
<string name="revanced_sb_skipped_filler">Ohitettu tangentti</string>
<string name="revanced_sb_skipped_filler">Toissijainen kohtaus ohitettiin</string>
<string name="revanced_sb_skipped_nomusic">Musiikiton osio ohitettiin</string>
<string name="revanced_sb_skipped_unsubmitted">Lähettämätön osio ohitettiin</string>
<string name="revanced_sb_skipped_multiple_segments">Useita osioita ohitettiin</string>
@@ -1254,7 +1254,7 @@ Oletko valmis lähettämään?"</string>
<string name="revanced_sb_new_segment_edit_by_hand_parse_error">Annettu aika on virheellinen</string>
<string name="revanced_sb_stats_title">Tilastot</string>
<!-- Shown in the settings preferences, and translations can be any text length. -->
<string name="revanced_sb_stats_connection_failure">Tilastot eivät tilapäisesti saatavilla (API ei ole käytettävissä)</string>
<string name="revanced_sb_stats_connection_failure">Tilastot eivät ole tilapäisesti saatavilla (API ei ole käytettävissä)</string>
<string name="revanced_sb_stats_loading">Ladataan...</string>
<string name="revanced_sb_stats_sb_disabled">SponsorBlock ei ole käytössä</string>
<string name="revanced_sb_stats_username">Käyttäjänimesi: &lt;b&gt;%s&lt;/b&gt;</string>
@@ -1265,11 +1265,11 @@ Oletko valmis lähettämään?"</string>
<string name="revanced_sb_stats_submissions">Olet luonut &lt;b&gt;%s&lt;/b&gt; osiota</string>
<string name="revanced_sb_stats_submissions_sum">Napauta tästä nähdäksesi osiosi</string>
<string name="revanced_sb_stats_saved_zero">SponsorBlock-tulostaulu</string>
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä &lt;b&gt;%s&lt;/b&gt; segmentiltä</string>
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä &lt;b&gt;%s&lt;/b&gt; osiolta</string>
<string name="revanced_sb_stats_saved_sum_zero">Napauta tästä nähdäksesi globaalit tilastot ja parhaat osallistujat</string>
<string name="revanced_sb_stats_saved_sum">Se on &lt;b&gt;%s&lt;/b&gt; heidän elämistään.&lt;br&gt;Napauta tästä nähdäksesi tulostaulun</string>
<string name="revanced_sb_stats_self_saved">Olet ohittanut &lt;b&gt;%s&lt;/b&gt; osiota</string>
<string name="revanced_sb_stats_self_saved_sum">Tuo on &lt;b&gt;%s&lt;/b&gt;</string>
<string name="revanced_sb_stats_self_saved_sum">Se on &lt;b&gt;%s&lt;/b&gt;</string>
<string name="revanced_sb_stats_self_saved_reset_title">Nollataanko ohitettujen osioiden laskuri?</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s tuntia %2$s minuuttia</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s minuuttia %2$s sekuntia</string>

View File

@@ -26,12 +26,12 @@ Second \"item\" text"</string>
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
<string name="revanced_custom_branding_name_entry_5">Personnalisé</string>
<string name="revanced_custom_branding_icon_title">Icône de l\'application</string>
<string name="revanced_custom_branding_icon_entry_1">Original</string>
<string name="revanced_custom_branding_icon_entry_1">Originale</string>
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimaliste</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced mis à l\'échelle</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced mise à l\'échelle</string>
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
<string name="revanced_custom_branding_icon_entry_5">Personnalisé</string>
<string name="revanced_custom_branding_icon_entry_5">Personnalisée</string>
</patch>
<patch id="misc.checks.checkEnvironmentPatch">
<string name="revanced_check_environment_failed_title">Les vérifications ont échoué</string>
@@ -1363,7 +1363,7 @@ Limitation : Il se peut que le bouton Retour dans la barre d'outils ne fonction
</patch>
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">Lecteur réduit</string>
<string name="revanced_miniplayer_screen_summary">Modifier le style du lecteur réduit à l\'intérieur de l\'application</string>
<string name="revanced_miniplayer_screen_summary">Modifiez le style du lecteur réduit intégré à l\'application</string>
<string name="revanced_miniplayer_type_title">Type de lecteur réduit</string>
<string name="revanced_miniplayer_type_entry_0">Désactivé</string>
<string name="revanced_miniplayer_type_entry_1">Par défaut</string>
@@ -1623,11 +1623,11 @@ Limitations :
<string name="revanced_spoof_video_streams_av1_title">Autoriser Android VR AV1</string>
<string name="revanced_spoof_video_streams_av1_summary_on">"Le codec vidéo est AVC (H.264), VP9 ou AV1
La lecture peut saccader ou perdre des images"</string>
La lecture peut être saccadée et des images peuvent être perdues"</string>
<string name="revanced_spoof_video_streams_av1_summary_off">Le codec vidéo est AVC (H.264) ou VP9</string>
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre peut utiliser le décodage AV1 logiciel.
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre permet l'utilisation du décodage AV1 logiciel.
La lecture vidéo avec AV1 peut saccader ou perdre des images."</string>
La lecture vidéo avec AV1 peut être saccadée et des images peuvent être perdues."</string>
<string name="revanced_spoof_video_streams_about_title">Effets secondaires de la falsification</string>
<string name="revanced_spoof_video_streams_about_experimental">• Client expérimental, peut cesser de fonctionner à tout moment</string>
<string name="revanced_spoof_video_streams_about_playback_failure">• Les vidéos sont susceptibles de s\'arrêter à 1:00, ou de ne pas être disponibles dans certaines régions</string>

View File

@@ -28,8 +28,8 @@ Second \"item\" text"</string>
<string name="revanced_custom_branding_icon_title">アプリアイコン</string>
<string name="revanced_custom_branding_icon_entry_1">オリジナル</string>
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
<string name="revanced_custom_branding_icon_entry_3">ReVanced (シンプル)</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced (ロゴ拡大)</string>
<string name="revanced_custom_branding_icon_entry_3">ReVancedシンプル</string>
<string name="revanced_custom_branding_icon_entry_4">ReVancedロゴ拡大</string>
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
<string name="revanced_custom_branding_icon_entry_5">カスタム</string>
</patch>
@@ -135,8 +135,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
</patch>
<patch id="misc.audio.forceOriginalAudioPatch">
<string name="revanced_force_original_audio_title">オリジナルの音声を強制的に使用</string>
<string name="revanced_force_original_audio_summary_on">オリジナルの音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックは使用ません</string>
<string name="revanced_force_original_audio_summary_off">アプリが選択した音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラック使用る場合があります</string>
<string name="revanced_force_original_audio_summary_on">オリジナルの音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックは使用されません</string>
<string name="revanced_force_original_audio_summary_off">アプリが選択した音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラック使用される場合があります</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">この機能を使用するには、「動画ストリームを偽装」のクライアントを Android Studio 以外の任意のクライアントに変更してください</string>
</patch>
@@ -304,8 +304,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_hide_medical_panels_summary_on">医療情報パネルは表示されません</string>
<string name="revanced_hide_medical_panels_summary_off">医療情報パネルは表示されます</string>
<string name="revanced_hide_quick_actions_title">クイック アクションを非表示</string>
<string name="revanced_hide_quick_actions_summary_on">全画面表示のクイック アクションは表示されません</string>
<string name="revanced_hide_quick_actions_summary_off">全画面表示のクイック アクションは表示されます</string>
<string name="revanced_hide_quick_actions_summary_on">全画面表示モードのクイック アクションは表示されません</string>
<string name="revanced_hide_quick_actions_summary_off">全画面表示モードのクイック アクションは表示されます</string>
<string name="revanced_hide_related_videos_title">関連動画を非表示</string>
<string name="revanced_hide_related_videos_summary_on">クイック アクション内の関連動画は表示されません</string>
<string name="revanced_hide_related_videos_summary_off">クイック アクション内の関連動画は表示されます</string>
@@ -313,17 +313,17 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_hide_subscribers_community_guidelines_summary_on">登録チャンネルのコミュニティ ガイドラインは非表示です</string>
<string name="revanced_hide_subscribers_community_guidelines_summary_off">登録チャンネルのコミュニティ ガイドラインは表示されます</string>
<string name="revanced_hide_timed_reactions_title">Timed Reaction を非表示</string>
<string name="revanced_hide_timed_reactions_summary_on">Timed Reaction とチャット欄のハートマーク アイコンは表示されません</string>
<string name="revanced_hide_timed_reactions_summary_off">Timed Reaction チャット欄ハートマー アイコンは表示されます</string>
<string name="revanced_hide_timed_reactions_summary_on">Timed reaction は表示されません\n\nライブ配信のチャット欄に常駐するハート マーク ボタンが非表示になります</string>
<string name="revanced_hide_timed_reactions_summary_off">Timed reaction は表示されます\n\nライブ配信のチャット欄ハート マーク ボタンが常駐します</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">「AI 生成による動画の要約」を非表示</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">「AI 生成による動画の要約」セクションは表示されません</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">「AI 生成による動画の要約」セクションは表示されます</string>
<string name="revanced_hide_ask_section_title">質問セクションを非表示</string>
<string name="revanced_hide_ask_section_summary_on">質問セクションは表示されません</string>
<string name="revanced_hide_ask_section_summary_off">質問セクションは表示されます</string>
<string name="revanced_hide_ask_section_title">質問する」を非表示</string>
<string name="revanced_hide_ask_section_summary_on">質問する」セクションは表示されません</string>
<string name="revanced_hide_ask_section_summary_off">質問する」セクションは表示されます</string>
<string name="revanced_hide_attributes_section_title">付随情報を非表示</string>
<string name="revanced_hide_attributes_section_summary_on">注目の場所 / ゲーム / 音楽 / 言及されている人物セクションは表示されません</string>
<string name="revanced_hide_attributes_section_summary_off">注目の場所 / ゲーム / 音楽 / 言及されている人物セクションは表示されます</string>
<string name="revanced_hide_attributes_section_summary_on">注目の場所 / ゲーム / 音楽 / 人物セクションは表示されません</string>
<string name="revanced_hide_attributes_section_summary_off">注目の場所 / ゲーム / 音楽 / 人物セクションは表示されます</string>
<string name="revanced_hide_chapters_section_title">チャプター セクションを非表示</string>
<string name="revanced_hide_chapters_section_summary_on">チャプター セクションは表示されません</string>
<string name="revanced_hide_chapters_section_summary_off">チャプター セクションは表示されます</string>
@@ -342,8 +342,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_hide_transcript_section_title">文字起こしセクションを非表示</string>
<string name="revanced_hide_transcript_section_summary_on">文字起こしセクションは表示されません</string>
<string name="revanced_hide_transcript_section_summary_off">文字起こしセクションは表示されます</string>
<string name="revanced_hide_description_components_screen_title">動画の概要欄</string>
<string name="revanced_hide_description_components_screen_summary">動画の概要欄のコンポーネントを表示または非表示にします</string>
<string name="revanced_hide_description_components_screen_title">概要欄</string>
<string name="revanced_hide_description_components_screen_summary">概要欄のコンポーネントを表示または非表示にします</string>
<string name="revanced_hide_filter_bar_screen_title">フィルタバー</string>
<string name="revanced_hide_filter_bar_screen_summary">フィード、関連動画、検索結果、および再生履歴でフィルタバーを表示または非表示にします</string>
<string name="revanced_hide_filter_bar_feed_in_feed_title">フィードで非表示</string>
@@ -456,12 +456,12 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_hide_keyword_content_about_summary">"ホーム / 登録チャンネル / 検索結果でキーワードに合致する動画を非表示にします
制限事項
• ショート動画はチャンネル名非表示にできない
• ショート動画はチャンネル名の合致では非表示にできない
• 一部の UI コンポーネントが残ってしまう場合がある
• キーワードを検索したとき、結果が表示されない場合がある"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">単語全体で合致</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">キーワードを二重引用符で囲むことで、動画のタイトルやチャンネル名単語の一部とキーワードが合致しないようにできます&lt;br&gt;&lt;br&gt;例えば、&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt;は、次の動画を非表示にします:&lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;しかし、次の動画は非表示にしません:&lt;b&gt;What does fair use mean?&lt;/b&gt;</string>
<string name="revanced_hide_keyword_content_about_whole_words_summary">キーワードを二重引用符で囲むことで、動画のタイトルやチャンネル名に含まれる単語の一部とキーワードが合致しないようにできます&lt;br&gt;&lt;br&gt;例えば、&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt;は、次の動画を非表示にします:&lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;しかし、次の動画は非表示にしません:&lt;b&gt;What does fair use mean?&lt;/b&gt;</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="revanced_hide_keyword_toast_invalid_common">使用できないキーワード: %s</string>
<string name="revanced_hide_keyword_toast_invalid_common_whole_word_required">二重引用符が必要なキーワード: %s</string>
@@ -496,8 +496,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_hide_self_sponsor_ads_summary_on">自己スポンサー カードは表示されません</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">自己スポンサー カードは表示されます</string>
<string name="revanced_hide_shopping_links_title">商品へのリンクを非表示</string>
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄にある商品へのリンクは表示されません</string>
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄にある商品へのリンクは表示されます</string>
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄商品へのリンクは表示されません</string>
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄商品へのリンクは表示されます</string>
<string name="revanced_hide_view_products_banner_title">「商品を表示」バナーを非表示</string>
<string name="revanced_hide_view_products_banner_summary_on">動画オーバーレイの「商品を表示」バナーは表示されません</string>
<string name="revanced_hide_view_products_banner_summary_off">動画オーバーレイの「商品を表示」バナーは表示されます</string>
@@ -614,12 +614,12 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_swipe_volume_sensitivity_summary">スワイプによる音量の変化量</string>
<string name="revanced_swipe_overlay_style_title">オーバーレイのスタイル</string>
<string name="revanced_swipe_overlay_style_entry_1">横型</string>
<string name="revanced_swipe_overlay_style_entry_2">横型 (シンプル - 画面上部)</string>
<string name="revanced_swipe_overlay_style_entry_3">横型 (シンプル - 画面中央)</string>
<string name="revanced_swipe_overlay_style_entry_2">横型シンプル - 画面上部</string>
<string name="revanced_swipe_overlay_style_entry_3">横型シンプル - 画面中央</string>
<string name="revanced_swipe_overlay_style_entry_4">円形</string>
<string name="revanced_swipe_overlay_style_entry_5">円形 (シンプル)</string>
<string name="revanced_swipe_overlay_style_entry_5">円形シンプル</string>
<string name="revanced_swipe_overlay_style_entry_6">縦型</string>
<string name="revanced_swipe_overlay_style_entry_7">縦型 (シンプル)</string>
<string name="revanced_swipe_overlay_style_entry_7">縦型シンプル</string>
<string name="revanced_swipe_change_video_title">スワイプによる動画の切り替えを有効化</string>
<string name="revanced_swipe_change_video_summary_on">全画面表示中に左 / 右にスワイプすると、前 / 次の動画に切り替わります</string>
<string name="revanced_swipe_change_video_summary_off">全画面表示中に左 / 右にスワイプしても、前 / 次の動画に切り替わりません</string>
@@ -741,7 +741,7 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
</patch>
<patch id="layout.hide.player.flyoutmenupanel.hidePlayerFlyoutMenuPatch">
<string name="revanced_hide_player_flyout_title">フライアウト メニュー</string>
<string name="revanced_hide_player_flyout_summary">プレーヤー オーバーレイの歯車ボタンから呼び出されるフライアウト メニューの項目を表示または非表示にします</string>
<string name="revanced_hide_player_flyout_summary">プレーヤー オーバーレイの歯車アイコンボタンから呼び出されるフライアウト メニューの項目を表示または非表示にします</string>
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_captions_title">「字幕」を非表示</string>
<string name="revanced_hide_player_flyout_captions_summary_on">「字幕」は表示されません</string>
@@ -967,13 +967,13 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_end_screen_suggested_video_summary_on">"終了画面の「関連動画」は表示されませんが、自動再生がオンの場合は関連動画が自動で再生されます
自動再生の設定は YouTube の設定で変更できます:
設定 → 再生 → 次の動画を自動再生"</string>
[設定] > [再生] > [次の動画を自動再生]"</string>
<string name="revanced_end_screen_suggested_video_summary_off">終了画面の「関連動画」は表示されます</string>
</patch>
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
<string name="revanced_hide_related_videos_overlay_title">関連動画オーバーレイを非表示</string>
<string name="revanced_hide_related_videos_overlay_summary_on">全画面表示の関連動画オーバーレイは表示されません</string>
<string name="revanced_hide_related_videos_overlay_summary_off">全画面表示の関連動画オーバーレイは表示されます</string>
<string name="revanced_hide_related_videos_overlay_summary_on">全画面表示モードの関連動画オーバーレイは表示されません</string>
<string name="revanced_hide_related_videos_overlay_summary_off">全画面表示モードの関連動画オーバーレイは表示されます</string>
</patch>
<patch id="layout.hide.time.hideTimestampPatch">
<string name="revanced_hide_timestamp_title">動画のタイムスタンプを非表示</string>
@@ -982,8 +982,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
</patch>
<patch id="layout.panels.popup.playerPopupPanelsPatch">
<string name="revanced_hide_player_popup_panels_title">プレーヤー ポップアップ パネルを非表示</string>
<string name="revanced_hide_player_popup_panels_summary_on">プレーヤー ポップアップ パネルは表示されません\n\nプレイリストやチャット欄などを閉じた状態で動画を開きます</string>
<string name="revanced_hide_player_popup_panels_summary_off">プレーヤー ポップアップ パネルは表示されます\n\nプレイリストやチャット欄などを展開した状態で動画を開きます</string>
<string name="revanced_hide_player_popup_panels_summary_on">プレーヤー ポップアップ パネルは表示されません\n\nプレイリストやライブ配信のチャット欄などを閉じた状態で動画を開きます</string>
<string name="revanced_hide_player_popup_panels_summary_off">プレーヤー ポップアップ パネルは表示されます\n\nプレイリストやライブ配信のチャット欄などを展開した状態で動画を開きます</string>
</patch>
<patch id="layout.player.fullscreen.exitFullscreenPatch">
<string name="revanced_exit_fullscreen_title">再生終了時に全画面表示を解除</string>
@@ -1159,9 +1159,9 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_sb_segments_interaction_sum">動画内に挿入される視聴者への高評価、チャンネル登録、フォローなどの時間的に短い催促。時間的に長い催促またはイベントなどの個別具体的なものに関する催促は、「視聴者への催促」ではなく「自己宣伝」に分類すべきです</string>
<string name="revanced_sb_segments_highlight">ハイライト</string>
<string name="revanced_sb_segments_highlight_sum">動画の中で最も重要な場面</string>
<string name="revanced_sb_segments_intro">幕間 / オープニング</string>
<string name="revanced_sb_segments_intro">幕間 / オープニング (OP)</string>
<string name="revanced_sb_segments_intro_sum">実際のコンテンツを含まない区間。一時停止、静止画、繰り返しアニメーションなど。情報を含むトランジッション (場面転換) は、このカテゴリーではありません</string>
<string name="revanced_sb_segments_outro">終了画面 / クレジット</string>
<string name="revanced_sb_segments_outro">終了画面 / クレジット (ED)</string>
<string name="revanced_sb_segments_outro_sum">クレジット、または YouTube の終了画面が表示される場面。情報を含む結論、まとめ部分は、このカテゴリーには含まれません</string>
<string name="revanced_sb_segments_hook">フック / あいさつ</string>
<string name="revanced_sb_segments_hook_sum">今後の動画のナレーション付きの予告編、および開幕と別れのあいさつ。重複しない内容や情報を追加する場面は含まれません</string>
@@ -1177,10 +1177,10 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_sb_skip_button_selfpromo">自己宣伝をスキップ</string>
<string name="revanced_sb_skip_button_interaction">催促をスキップ</string>
<string name="revanced_sb_skip_button_highlight">ハイライトまでスキップ</string>
<string name="revanced_sb_skip_button_intro_beginning">オープニングをスキップ</string>
<string name="revanced_sb_skip_button_intro_beginning">OP をスキップ</string>
<string name="revanced_sb_skip_button_intro_middle">幕間をスキップ</string>
<string name="revanced_sb_skip_button_intro_end">幕間をスキップ</string>
<string name="revanced_sb_skip_button_outro">エンディングをスキップ</string>
<string name="revanced_sb_skip_button_outro">ED をスキップ</string>
<string name="revanced_sb_skip_button_hook">フックをスキップ</string>
<string name="revanced_sb_skip_button_preview_beginning">予告編をスキップ</string>
<string name="revanced_sb_skip_button_preview_middle">予告編をスキップ</string>
@@ -1192,10 +1192,10 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
<string name="revanced_sb_skipped_selfpromo">自己宣伝をスキップしました</string>
<string name="revanced_sb_skipped_interaction">催促をスキップしました</string>
<string name="revanced_sb_skipped_highlight">ハイライトまでスキップしました</string>
<string name="revanced_sb_skipped_intro_beginning">オープニングをスキップしました</string>
<string name="revanced_sb_skipped_intro_beginning">OP をスキップしました</string>
<string name="revanced_sb_skipped_intro_middle">幕間をスキップしました</string>
<string name="revanced_sb_skipped_intro_end">幕間をスキップしました</string>
<string name="revanced_sb_skipped_outro">エンディングをスキップしました</string>
<string name="revanced_sb_skipped_outro">ED をスキップしました</string>
<string name="revanced_sb_skipped_hook">フックをスキップしました</string>
<string name="revanced_sb_skipped_preview_beginning">予告編をスキップしました</string>
<string name="revanced_sb_skipped_preview_middle">予告編をスキップしました</string>
@@ -1309,7 +1309,7 @@ Automotive レイアウト
<string name="revanced_spoof_app_version_target_title">アプリバージョンの偽装先</string>
<string name="revanced_spoof_app_version_target_entry_1">20.13.41 - アクション ボタンの文字表示を復元</string>
<string name="revanced_spoof_app_version_target_entry_2">20.05.46 - 文字起こし機能を復元</string>
<string name="revanced_spoof_app_version_target_entry_3">19.35.36 - 古いショート プレーヤーのアイコンを復元</string>
<string name="revanced_spoof_app_version_target_entry_3">19.35.36 - ショート プレーヤーの古いアイコンを復元</string>
<string name="revanced_spoof_app_version_target_entry_4">19.01.34 - 古いナビゲーション アイコンを復元</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
@@ -1359,7 +1359,7 @@ Automotive レイアウト
<string name="revanced_shorts_autoplay_title">ショート動画の自動再生</string>
<string name="revanced_shorts_autoplay_summary_on">ショート動画は自動再生されます</string>
<string name="revanced_shorts_autoplay_summary_off">ショート動画はループ再生されます</string>
<string name="revanced_shorts_autoplay_background_title">ショート動画の自動再生バックグラウンド</string>
<string name="revanced_shorts_autoplay_background_title">ショート動画の自動再生 (バックグラウンド)</string>
<string name="revanced_shorts_autoplay_background_summary_on">バックグラウンドのショート動画は自動再生されます</string>
<string name="revanced_shorts_autoplay_background_summary_off">バックグラウンドのショート動画はループ再生されます</string>
</patch>
@@ -1369,7 +1369,7 @@ Automotive レイアウト
<string name="revanced_miniplayer_type_title">ミニプレーヤーの種類</string>
<string name="revanced_miniplayer_type_entry_0">無効</string>
<string name="revanced_miniplayer_type_entry_1">デフォルト</string>
<string name="revanced_miniplayer_type_entry_2">横長 (旧タイプ)</string>
<string name="revanced_miniplayer_type_entry_2">旧タイプ (横長)</string>
<string name="revanced_miniplayer_type_entry_3">タブレット</string>
<string name="revanced_miniplayer_type_entry_4">新タイプ 1</string>
<string name="revanced_miniplayer_type_entry_5">新タイプ 2</string>
@@ -1381,8 +1381,8 @@ Automotive レイアウト
<string name="revanced_miniplayer_double_tap_action_title">ダブルタップとピンチによるサイズ変更を有効化</string>
<string name="revanced_miniplayer_double_tap_action_summary_on">"ダブルタップとピンチによるサイズ変更は有効です
• ダブルタップするとミニプレーヤーのサイズが大きくなる
• もう一度ダブルタップすると元のサイズに戻る"</string>
• ダブルタップするとミニプレーヤーのサイズが大きくなる
• もう一度ダブルタップすると元のサイズに戻る"</string>
<string name="revanced_miniplayer_double_tap_action_summary_off">ダブルタップとピンチによるサイズ変更は無効です</string>
<string name="revanced_miniplayer_disable_drag_and_drop_title">ドラッグ&ドロップを無効化</string>
<string name="revanced_miniplayer_disable_drag_and_drop_summary_on">ドラッグ&ドロップは無効です</string>
@@ -1433,7 +1433,7 @@ Automotive レイアウト
<string name="revanced_header_logo_entry_1">デフォルト</string>
<string name="revanced_header_logo_entry_2">標準</string>
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
<string name="revanced_header_logo_entry_5">ReVanced (シンプル)</string>
<string name="revanced_header_logo_entry_5">ReVancedシンプル</string>
<string name="revanced_header_logo_entry_6">カスタム</string>
</patch>
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
@@ -1546,13 +1546,13 @@ Automotive レイアウト
<string name="revanced_remember_video_quality_last_selected_toast_title">画質の変更時にトーストを表示</string>
<string name="revanced_remember_video_quality_last_selected_toast_summary_on">デフォルトの画質が変更された場合にトースト通知が表示されます</string>
<string name="revanced_remember_video_quality_last_selected_toast_summary_off">デフォルトの画質が変更された場合にトースト通知は表示されません</string>
<string name="revanced_video_quality_default_wifi_title">デフォルトの画質Wi-Fi</string>
<string name="revanced_video_quality_default_mobile_title">デフォルトの画質携帯回線</string>
<string name="revanced_video_quality_default_wifi_title">デフォルトの画質 (Wi-Fi)</string>
<string name="revanced_video_quality_default_mobile_title">デフォルトの画質 (携帯回線)</string>
<string name="revanced_remember_shorts_quality_last_selected_title">ショートの画質の変更を保存</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">画質の変更はすべてのショート動画に適用されます</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">画質の変更は現在のショート動画にのみ適用されます</string>
<string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質Wi-Fi</string>
<string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質携帯回線</string>
<string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質 (Wi-Fi)</string>
<string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質 (携帯回線)</string>
<string name="revanced_remember_video_quality_mobile">携帯回線</string>
<string name="revanced_remember_video_quality_wifi">Wi-Fi</string>
<string name="revanced_remember_video_quality_toast">デフォルトの画質の変更 (%1$s): %2$s</string>

View File

@@ -885,8 +885,8 @@ YouTube Premium 사용자라면 이 설정은 필요하지 않을 수 있습니
<string name="revanced_hide_shorts_new_posts_button_summary_on">새로운 게시물 버튼이 숨겨집니다</string>
<string name="revanced_hide_shorts_new_posts_button_summary_off">새로운 게시물 버튼이 표시됩니다</string>
<string name="revanced_hide_shorts_paused_overlay_buttons_title">일시 정지 오버레이 버튼 숨기기</string>
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_on">일시 정지 오버레이 버튼이 숨겨집니다</string>
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_off">일시 정지 오버레이 버튼이 표시됩니다</string>
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_on">플레이어 왼쪽 상단에서 다음 버튼이 숨겨집니다\n• 구독 &amp; 라이브 &amp; 렌즈 &amp; 트렌드 &amp; 쇼핑</string>
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_off">플레이어 왼쪽 상단에서 다음 버튼이 표시됩니다\n• 구독 &amp; 라이브 &amp; 렌즈 &amp; 트렌드 &amp; 쇼핑</string>
<string name="revanced_hide_shorts_preview_comment_title">댓글 미리보기 숨기기</string>
<string name="revanced_hide_shorts_preview_comment_summary_on">댓글 미리보기가 숨겨집니다</string>
<string name="revanced_hide_shorts_preview_comment_summary_off">댓글 미리보기가 표시됩니다</string>

View File

@@ -378,12 +378,12 @@ Nếu cài đặt này được bật và Doodle đang hiển thị tại khu v
<string name="revanced_hide_visit_store_button_summary_off">Nút Chuyển đến cửa hàng được hiển thị</string>
<string name="revanced_comments_screen_title">Bình luận</string>
<string name="revanced_comments_screen_summary">Ẩn hoặc hiện các thành phần bình luận</string>
<string name="revanced_hide_comments_ai_chat_summary_title">Ẩn tóm tắt cuộc trò chuyện AI</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">Tóm tắt cuộc trò chuyện AI đã bị ẩn</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">Tóm tắt cuộc trò chuyện AI được hiển thị</string>
<string name="revanced_hide_comments_ai_summary_title">Ẩn tóm tắt bình luận AI</string>
<string name="revanced_hide_comments_ai_summary_summary_on">Tóm tắt bình luận AI đã bị ẩn</string>
<string name="revanced_hide_comments_ai_summary_summary_off">Tóm tắt bình luận AI được hiển thị</string>
<string name="revanced_hide_comments_ai_chat_summary_title">Ẩn tóm tắt cuộc trò chuyện do AI tạo</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">Tóm tắt cuộc trò chuyện do AI tạo đã bị ẩn</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">Tóm tắt cuộc trò chuyện do AI tạo được hiển thị</string>
<string name="revanced_hide_comments_ai_summary_title">Ẩn tóm tắt bình luận do AI tạo</string>
<string name="revanced_hide_comments_ai_summary_summary_on">Tóm tắt bình luận do AI tạo đã bị ẩn</string>
<string name="revanced_hide_comments_ai_summary_summary_off">Tóm tắt bình luận do AI tạo được hiển thị</string>
<string name="revanced_hide_comments_channel_guidelines_title">Ẩn nguyên tắc kênh</string>
<string name="revanced_hide_comments_channel_guidelines_summary_on">Nguyên tắc kênh đã bị ẩn</string>
<string name="revanced_hide_comments_channel_guidelines_summary_off">Nguyên tắc kênh được hiển thị</string>
@@ -912,12 +912,12 @@ Nếu thay đổi cài đặt này không có hiệu lực, hãy thử chuyển
<string name="revanced_hide_shorts_upcoming_button_title">Ẩn nút Sắp diễn ra</string>
<string name="revanced_hide_shorts_upcoming_button_summary_on">Nút sắp diễn ra đã bị ẩn</string>
<string name="revanced_hide_shorts_upcoming_button_summary_off">Nút sắp diễn ra được hiển thị</string>
<string name="revanced_hide_shorts_use_sound_button_title">Ẩn nút \"Sử dụng âm thanh này\"</string>
<string name="revanced_hide_shorts_use_sound_button_summary_on">Nút \"Sử dụng âm thanh này\" đã bị ẩn</string>
<string name="revanced_hide_shorts_use_sound_button_summary_off">Nút \"Sử dụng âm thanh này\" được hiển thị</string>
<string name="revanced_hide_shorts_use_template_button_title">Ẩn nút \"Sử dụng mẫu này\"</string>
<string name="revanced_hide_shorts_use_template_button_summary_on">Nút \"Sử dụng mẫu này\" đã bị ẩn</string>
<string name="revanced_hide_shorts_use_template_button_summary_off">Nút \"Sử dụng mẫu này\" được hiển thị</string>
<string name="revanced_hide_shorts_use_sound_button_title">Ẩn nút ng âm thanh này</string>
<string name="revanced_hide_shorts_use_sound_button_summary_on">Nút ng âm thanh này đã bị ẩn</string>
<string name="revanced_hide_shorts_use_sound_button_summary_off">Nút ng âm thanh này được hiển thị</string>
<string name="revanced_hide_shorts_use_template_button_title">Ẩn nút Sử dụng mẫu này</string>
<string name="revanced_hide_shorts_use_template_button_summary_on">Nút sử dụng mẫu này đã bị ẩn</string>
<string name="revanced_hide_shorts_use_template_button_summary_off">Nút sử dụng mẫu này được hiển thị</string>
<string name="revanced_hide_shorts_like_fountain_title">Ẩn hiệu ứng đài phun nút Thích</string>
<string name="revanced_hide_shorts_like_fountain_summary_on">Hiệu ứng đài phun nút thích đã bị ẩn</string>
<string name="revanced_hide_shorts_like_fountain_summary_off">Hiệu ứng đài phun nút thích được hiển thị</string>

View File

@@ -5,33 +5,39 @@
android:height="108dp"
android:viewportWidth="256"
android:viewportHeight="256">
<!-- Android launcher can hide the background layer if it's black or nearly black.
The dark background is needed to see the V shape in day mode. To prevent hiding
the layer it must be added to the foreground. -->
<path
android:pathData="M0,0 L256,0 L256,256 L0,256 Z"
android:fillColor="#1B1B1B" />
<group android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<!-- Android launcher can hide the background layer if it's black or nearly black.
The dark background is needed to see the V shape in day mode. To prevent hiding
the layer it must be added to the foreground. -->
<path
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="128"
android:startY="-0"
android:endX="128"
android:endY="254.6"
android:type="linear">
<item android:offset="0" android:color="#FFF04E98"/>
<item android:offset="0.5" android:color="#FF5F65D4"/>
<item android:offset="1" android:color="#FF4E98F0"/>
</gradient>
</aapt:attr>
</path>
</group>
android:fillColor="#1B1B1B"
android:pathData="M0,0 L256,0 L256,256 L0,256 Z" />
<group
android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<path
android:fillColor="#FFFFFF"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z" />
<path android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="128"
android:endY="254.6"
android:startX="128"
android:startY="-0"
android:type="linear">
<item
android:color="#FFF04E98"
android:offset="0" />
<item
android:color="#FF5F65D4"
android:offset="0.5" />
<item
android:color="#FF4E98F0"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View File

@@ -5,47 +5,59 @@
android:height="108dp"
android:viewportWidth="800"
android:viewportHeight="800">
<group android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="200"
android:translateY="200">
<path
android:pathData="M400,400m-400,0a400,400 0,1 1,800 0a400,400 0,1 1,-800 0"
android:fillColor="#1B1B1B"/>
<path
android:pathData="M400,0c220.77,0 400,179.23 400,400c-0,220.77 -179.23,400 -400,400c-220.77,-0 -400,-179.23 -400,-400c0,-220.77 179.23,-400 400,-400ZM400,36c200.9,-0 364,163.1 364,364c0,200.9 -163.1,364 -364,364c-200.9,0 -364,-163.1 -364,-364c-0,-200.9 163.1,-364 364,-364Z"
android:strokeLineJoin="round"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="400"
android:startY="0"
android:endX="400"
android:endY="800"
android:type="linear">
<item android:offset="0" android:color="#FFF04E98"/>
<item android:offset="0.5" android:color="#FF5F65D4"/>
<item android:offset="1" android:color="#FF4E98F0"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M538.74,269.87c1.48,-3.38 1.16,-7.28 -0.86,-10.37c-2.02,-3.09 -5.46,-4.95 -9.16,-4.95c-5.15,0 -10.44,0 -14.16,0c-3.1,0 -5.91,1.83 -7.15,4.67c-12.47,28.4 -78.27,178.27 -100.25,228.33c-1.25,2.84 -4.05,4.67 -7.15,4.67c-3.1,0 -5.91,-1.83 -7.15,-4.67c-21.98,-50.06 -87.78,-199.93 -100.25,-228.33c-1.25,-2.84 -4.05,-4.67 -7.15,-4.67c-3.73,0 -9.02,0 -14.16,0c-3.69,0 -7.14,1.86 -9.16,4.95c-2.02,3.09 -2.34,6.99 -0.86,10.37c23.56,53.77 101.87,232.52 117.87,269.03c1.74,3.98 5.67,6.55 10.02,6.55c6.29,-0 15.41,-0 21.7,-0c4.34,-0 8.27,-2.57 10.02,-6.55c16,-36.51 94.32,-215.27 117.87,-269.03Z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M408.12,395.31c-1.67,2.9 -4.77,4.69 -8.12,4.69c-3.35,-0 -6.44,-1.79 -8.12,-4.69c-17,-29.44 -56.16,-97.26 -73.15,-126.7c-1.67,-2.9 -1.67,-6.47 0,-9.38c1.67,-2.9 4.77,-4.69 8.12,-4.69c33.99,0 112.31,0 146.31,0c3.35,0 6.44,1.79 8.12,4.69c1.67,2.9 1.67,6.47 -0,9.38c-17,29.44 -56.16,97.26 -73.15,126.7Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="400"
android:startY="254.54"
android:endX="400"
android:endY="543.86"
android:type="linear">
<item android:offset="0" android:color="#FFF04E98"/>
<item android:offset="0.5" android:color="#FF5F65D4"/>
<item android:offset="1" android:color="#FF4E98F0"/>
</gradient>
</aapt:attr>
</path>
</group>
<group
android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="200"
android:translateY="200">
<path
android:fillColor="#1B1B1B"
android:pathData="M400,400m-400,0a400,400 0,1 1,800 0a400,400 0,1 1,-800 0" />
<path
android:fillType="evenOdd"
android:pathData="M400,0c220.77,0 400,179.23 400,400c-0,220.77 -179.23,400 -400,400c-220.77,-0 -400,-179.23 -400,-400c0,-220.77 179.23,-400 400,-400ZM400,36c200.9,-0 364,163.1 364,364c0,200.9 -163.1,364 -364,364c-200.9,0 -364,-163.1 -364,-364c-0,-200.9 163.1,-364 364,-364Z"
android:strokeLineJoin="round">
<aapt:attr name="android:fillColor">
<gradient
android:endX="400"
android:endY="800"
android:startX="400"
android:startY="0"
android:type="linear">
<item
android:color="#FFF04E98"
android:offset="0" />
<item
android:color="#FF5F65D4"
android:offset="0.5" />
<item
android:color="#FF4E98F0"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:pathData="M538.74,269.87c1.48,-3.38 1.16,-7.28 -0.86,-10.37c-2.02,-3.09 -5.46,-4.95 -9.16,-4.95c-5.15,0 -10.44,0 -14.16,0c-3.1,0 -5.91,1.83 -7.15,4.67c-12.47,28.4 -78.27,178.27 -100.25,228.33c-1.25,2.84 -4.05,4.67 -7.15,4.67c-3.1,0 -5.91,-1.83 -7.15,-4.67c-21.98,-50.06 -87.78,-199.93 -100.25,-228.33c-1.25,-2.84 -4.05,-4.67 -7.15,-4.67c-3.73,0 -9.02,0 -14.16,0c-3.69,0 -7.14,1.86 -9.16,4.95c-2.02,3.09 -2.34,6.99 -0.86,10.37c23.56,53.77 101.87,232.52 117.87,269.03c1.74,3.98 5.67,6.55 10.02,6.55c6.29,-0 15.41,-0 21.7,-0c4.34,-0 8.27,-2.57 10.02,-6.55c16,-36.51 94.32,-215.27 117.87,-269.03Z" />
<path android:pathData="M408.12,395.31c-1.67,2.9 -4.77,4.69 -8.12,4.69c-3.35,-0 -6.44,-1.79 -8.12,-4.69c-17,-29.44 -56.16,-97.26 -73.15,-126.7c-1.67,-2.9 -1.67,-6.47 0,-9.38c1.67,-2.9 4.77,-4.69 8.12,-4.69c33.99,0 112.31,0 146.31,0c3.35,0 6.44,1.79 8.12,4.69c1.67,2.9 1.67,6.47 -0,9.38c-17,29.44 -56.16,97.26 -73.15,126.7Z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="400"
android:endY="543.86"
android:startX="400"
android:startY="254.54"
android:type="linear">
<item
android:color="#FFF04E98"
android:offset="0" />
<item
android:color="#FF5F65D4"
android:offset="0.5" />
<item
android:color="#FF4E98F0"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View File

@@ -5,33 +5,39 @@
android:height="108dp"
android:viewportWidth="256"
android:viewportHeight="256">
<!-- Android launcher can hide the background layer if it's black or nearly black.
The dark background is needed to see the V shape in day mode. To prevent hiding
the layer it must be added to the foreground. -->
<path
android:pathData="M0,0 L256,0 L256,256 L0,256 Z"
android:fillColor="#000000" />
<group android:scaleX="0.3"
android:scaleY="0.3"
android:translateX="89.6"
android:translateY="89.6">
<!-- Android launcher can hide the background layer if it's black or nearly black.
The dark background is needed to see the V shape in day mode. To prevent hiding
the layer it must be added to the foreground. -->
<path
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="128"
android:startY="0"
android:endX="128"
android:endY="254.6"
android:type="linear">
<item android:offset="0" android:color="#FFF04E98"/>
<item android:offset="0.5" android:color="#FF5F65D4"/>
<item android:offset="1" android:color="#FF4E98F0"/>
</gradient>
</aapt:attr>
</path>
</group>
android:fillColor="#000000"
android:pathData="M0,0 L256,0 L256,256 L0,256 Z" />
<group
android:scaleX="0.3"
android:scaleY="0.3"
android:translateX="89.6"
android:translateY="89.6">
<path
android:fillColor="#FFFFFF"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z" />
<path android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="128"
android:endY="254.6"
android:startX="128"
android:startY="0"
android:type="linear">
<item
android:color="#FFF04E98"
android:offset="0" />
<item
android:color="#FF5F65D4"
android:offset="0.5" />
<item
android:color="#FF4E98F0"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View File

@@ -4,15 +4,16 @@
android:height="108dp"
android:viewportWidth="256"
android:viewportHeight="256">
<group android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<path
android:fillColor="#ff000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z"/>
</group>
<group
android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<path
android:fillColor="#FF000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z" />
<path
android:fillColor="#FF000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z" />
</group>
</vector>

View File

@@ -4,15 +4,16 @@
android:height="108dp"
android:viewportWidth="256"
android:viewportHeight="256">
<group android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<path
android:fillColor="#ff000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z"/>
</group>
<group
android:scaleX="0.24"
android:scaleY="0.24"
android:translateX="97.28"
android:translateY="97.28">
<path
android:fillColor="#FF000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z" />
<path
android:fillColor="#FF000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z" />
</group>
</vector>

View File

@@ -4,20 +4,21 @@
android:height="108dp"
android:viewportWidth="800"
android:viewportHeight="800">
<group android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="200"
android:translateY="200">
<path
android:fillColor="#ff000000"
android:pathData="M400,0c220.77,0 400,179.23 400,400c-0,220.77 -179.23,400 -400,400c-220.77,-0 -400,-179.23 -400,-400c0,-220.77 179.23,-400 400,-400ZM400,36c200.9,-0 364,163.1 364,364c0,200.9 -163.1,364 -364,364c-200.9,0 -364,-163.1 -364,-364c-0,-200.9 163.1,-364 364,-364Z"
android:strokeLineJoin="round"
android:fillType="evenOdd"/>
<path
android:fillColor="#ff000000"
android:pathData="M538.74,269.87c1.48,-3.38 1.16,-7.28 -0.86,-10.37c-2.02,-3.09 -5.46,-4.95 -9.16,-4.95c-5.15,0 -10.44,0 -14.16,0c-3.1,0 -5.91,1.83 -7.15,4.67c-12.47,28.4 -78.27,178.27 -100.25,228.33c-1.25,2.84 -4.05,4.67 -7.15,4.67c-3.1,0 -5.91,-1.83 -7.15,-4.67c-21.98,-50.06 -87.78,-199.93 -100.25,-228.33c-1.25,-2.84 -4.05,-4.67 -7.15,-4.67c-3.73,0 -9.02,0 -14.16,0c-3.69,0 -7.14,1.86 -9.16,4.95c-2.02,3.09 -2.34,6.99 -0.86,10.37c23.56,53.77 101.87,232.52 117.87,269.03c1.74,3.98 5.67,6.55 10.02,6.55c6.29,-0 15.41,-0 21.7,-0c4.34,-0 8.27,-2.57 10.02,-6.55c16,-36.51 94.32,-215.27 117.87,-269.03Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M408.12,395.31c-1.67,2.9 -4.77,4.69 -8.12,4.69c-3.35,-0 -6.44,-1.79 -8.12,-4.69c-17,-29.44 -56.16,-97.26 -73.15,-126.7c-1.67,-2.9 -1.67,-6.47 0,-9.38c1.67,-2.9 4.77,-4.69 8.12,-4.69c33.99,0 112.31,0 146.31,0c3.35,0 6.44,1.79 8.12,4.69c1.67,2.9 1.67,6.47 -0,9.38c-17,29.44 -56.16,97.26 -73.15,126.7Z"/>
</group>
<group
android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="200"
android:translateY="200">
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M400,0c220.77,0 400,179.23 400,400c-0,220.77 -179.23,400 -400,400c-220.77,-0 -400,-179.23 -400,-400c0,-220.77 179.23,-400 400,-400ZM400,36c200.9,-0 364,163.1 364,364c0,200.9 -163.1,364 -364,364c-200.9,0 -364,-163.1 -364,-364c-0,-200.9 163.1,-364 364,-364Z"
android:strokeLineJoin="round" />
<path
android:fillColor="#FF000000"
android:pathData="M538.74,269.87c1.48,-3.38 1.16,-7.28 -0.86,-10.37c-2.02,-3.09 -5.46,-4.95 -9.16,-4.95c-5.15,0 -10.44,0 -14.16,0c-3.1,0 -5.91,1.83 -7.15,4.67c-12.47,28.4 -78.27,178.27 -100.25,228.33c-1.25,2.84 -4.05,4.67 -7.15,4.67c-3.1,0 -5.91,-1.83 -7.15,-4.67c-21.98,-50.06 -87.78,-199.93 -100.25,-228.33c-1.25,-2.84 -4.05,-4.67 -7.15,-4.67c-3.73,0 -9.02,0 -14.16,0c-3.69,0 -7.14,1.86 -9.16,4.95c-2.02,3.09 -2.34,6.99 -0.86,10.37c23.56,53.77 101.87,232.52 117.87,269.03c1.74,3.98 5.67,6.55 10.02,6.55c6.29,-0 15.41,-0 21.7,-0c4.34,-0 8.27,-2.57 10.02,-6.55c16,-36.51 94.32,-215.27 117.87,-269.03Z" />
<path
android:fillColor="#FF000000"
android:pathData="M408.12,395.31c-1.67,2.9 -4.77,4.69 -8.12,4.69c-3.35,-0 -6.44,-1.79 -8.12,-4.69c-17,-29.44 -56.16,-97.26 -73.15,-126.7c-1.67,-2.9 -1.67,-6.47 0,-9.38c1.67,-2.9 4.77,-4.69 8.12,-4.69c33.99,0 112.31,0 146.31,0c3.35,0 6.44,1.79 8.12,4.69c1.67,2.9 1.67,6.47 -0,9.38c-17,29.44 -56.16,97.26 -73.15,126.7Z" />
</group>
</vector>

View File

@@ -4,15 +4,16 @@
android:height="108dp"
android:viewportWidth="256"
android:viewportHeight="256">
<group android:scaleX="0.3"
android:scaleY="0.3"
android:translateX="89.6"
android:translateY="89.6">
<path
android:fillColor="#ff000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z"/>
</group>
<group
android:scaleX="0.3"
android:scaleY="0.3"
android:translateX="89.6"
android:translateY="89.6">
<path
android:fillColor="#FF000000"
android:pathData="M250.09,13.49C251.39,10.51 251.11,7.08 249.33,4.36C247.55,1.64 244.52,0 241.27,0L228.81,0C226.08,0 223.61,1.62 222.51,4.11C211.54,29.1 153.63,160.99 134.29,205.04C133.2,207.54 130.73,209.15 128,209.15C125.27,209.15 122.8,207.54 121.7,205.04C102.36,160.99 44.46,29.1 33.49,4.11C32.39,1.62 29.92,0 27.19,0L14.73,0C11.48,0 8.45,1.64 6.67,4.36C4.89,7.08 4.61,10.51 5.91,13.49C26.64,60.8 95.56,218.1 109.63,250.24C111.17,253.74 114.63,256 118.45,256L137.55,256C141.37,256 144.83,253.74 146.36,250.24C160.44,218.1 229.36,60.8 250.09,13.49Z" />
<path
android:fillColor="#FF000000"
android:pathData="M135.14,123.87C133.67,126.43 130.94,128 128,128C125.05,128 122.33,126.43 120.85,123.87C105.89,97.97 71.44,38.28 56.48,12.37C55,9.82 55,6.68 56.48,4.12C57.95,1.57 60.68,-0 63.62,-0L192.37,-0C195.32,-0 198.04,1.57 199.52,4.12C200.99,6.68 200.99,9.82 199.52,12.37C184.56,38.28 150.1,97.97 135.14,123.87Z" />
</group>
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- Path must be white to ensure the icon appears white in the expanded status bar panel. -->
<path
android:fillColor="#FFFFFF"
android:pathData="M4.03516,3 C3.80859,3,3.59375,3.11719,3.46875,3.30469 C3.34375,3.49609,3.32422,3.73828,3.41406,3.94922 C4.87109,7.27344,9.71875,18.3359,10.707,20.5938 C10.8164,20.8398,11.0586,21,11.3281,21 L12.6719,21 C12.9375,21,13.1836,20.8398,13.293,20.5938 C14.2813,18.3359,19.1289,7.27344,20.5859,3.94922 C20.6758,3.73828,20.6563,3.49609,20.5313,3.30469 C20.4063,3.11719,20.1914,3,19.9648,3 L19.0898,3 C18.8984,3,18.7227,3.11328,18.6445,3.28906 C17.875,5.04688,13.8008,14.3203,12.4414,17.418 C12.3672,17.5938,12.1914,17.707,12,17.707 C11.8086,17.707,11.6328,17.5938,11.5586,17.418 C10.1992,14.3203,6.125,5.04688,5.35547,3.28906 C5.27734,3.11328,5.10156,3,4.91016,3 Z M7.47266,3 C7.26563,3,7.07422,3.10938,6.97266,3.28906 C6.86719,3.46875,6.86719,3.69141,6.97266,3.87109 C8.02344,5.69141,10.4453,9.88672,11.4961,11.7109 C11.6016,11.8906,11.793,12,12,12 C12.207,12,12.3984,11.8906,12.5039,11.7109 C13.5547,9.88672,15.9766,5.69141,17.0273,3.87109 C17.1328,3.69141,17.1328,3.46875,17.0273,3.28906 C16.9258,3.10938,16.7344,3,16.5273,3 Z M7.47266,3" />
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- Path must be white to ensure the icon appears white in the expanded status bar panel. -->
<path
android:fillColor="#FFFFFF"
android:pathData="M4.03516,3 C3.80859,3,3.59375,3.11719,3.46875,3.30469 C3.34375,3.49609,3.32422,3.73828,3.41406,3.94922 C4.87109,7.27344,9.71875,18.3359,10.707,20.5938 C10.8164,20.8398,11.0586,21,11.3281,21 L12.6719,21 C12.9375,21,13.1836,20.8398,13.293,20.5938 C14.2813,18.3359,19.1289,7.27344,20.5859,3.94922 C20.6758,3.73828,20.6563,3.49609,20.5313,3.30469 C20.4063,3.11719,20.1914,3,19.9648,3 L19.0898,3 C18.8984,3,18.7227,3.11328,18.6445,3.28906 C17.875,5.04688,13.8008,14.3203,12.4414,17.418 C12.3672,17.5938,12.1914,17.707,12,17.707 C11.8086,17.707,11.6328,17.5938,11.5586,17.418 C10.1992,14.3203,6.125,5.04688,5.35547,3.28906 C5.27734,3.11328,5.10156,3,4.91016,3 Z M7.47266,3 C7.26563,3,7.07422,3.10938,6.97266,3.28906 C6.86719,3.46875,6.86719,3.69141,6.97266,3.87109 C8.02344,5.69141,10.4453,9.88672,11.4961,11.7109 C11.6016,11.8906,11.793,12,12,12 C12.207,12,12.3984,11.8906,12.5039,11.7109 C13.5547,9.88672,15.9766,5.69141,17.0273,3.87109 C17.1328,3.69141,17.1328,3.46875,17.0273,3.28906 C16.9258,3.10938,16.7344,3,16.5273,3 Z M7.47266,3" />
</vector>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr format="reference|color" name="splash_custom_seekbar_color"/>
</resources>