Merge "Add perf test for Korean phrase line break"
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 64ba6d1..7bd5921 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -223,6 +223,27 @@
}
}
+ /** Tests creating and starting a new user. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void createAndStartUser_realistic() throws RemoteException {
+ while (mRunner.keepRunning()) {
+ Log.d(TAG, "Starting timer");
+ final int userId = createUserNoFlags();
+
+ // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
+ // ACTION_USER_STARTED.
+ runThenWaitForBroadcasts(userId, () -> {
+ mIam.startUserInBackground(userId);
+ }, Intent.ACTION_USER_STARTED);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/**
* Tests starting an uninitialized user.
* Measures the time until ACTION_USER_STARTED is received.
@@ -299,6 +320,29 @@
}
}
+ /**
+ * Tests starting & unlocking an uninitialized user.
+ * Measures the time until unlock listener is triggered and user is unlocked.
+ */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void startAndUnlockUser_realistic() throws RemoteException {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int userId = createUserNoFlags();
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ // Waits for UserState.mUnlockProgress.finish().
+ startUserInBackgroundAndWaitForUnlock(userId);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests switching to an uninitialized user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser() throws Exception {
@@ -527,7 +571,7 @@
removeUser(userId);
}
- /** Tests reaching LOOKED_BOOT_COMPLETE when switching to uninitialized user. */
+ /** Tests reaching LOCKED_BOOT_COMPLETE when switching to uninitialized user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void lockedBootCompleted() throws RemoteException {
while (mRunner.keepRunning()) {
@@ -550,6 +594,29 @@
}
}
+ /** Tests reaching LOCKED_BOOT_COMPLETE when switching to uninitialized user. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void lockedBootCompleted_realistic() throws RemoteException {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int startUser = ActivityManager.getCurrentUser();
+ final int userId = createUserNoFlags();
+
+ waitCoolDownPeriod();
+ mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> {
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+ mAm.switchUser(userId);
+ }, () -> fail("Failed to achieve onLockedBootComplete for user " + userId));
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ switchUserNoCheck(startUser);
+ removeUser(userId);
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests stopping an ephemeral foreground user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void ephemeralUserStopped() throws RemoteException {
@@ -579,6 +646,33 @@
}
}
+ /** Tests stopping an ephemeral foreground user. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void ephemeralUserStopped_realistic() throws RemoteException {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int startUser = ActivityManager.getCurrentUser();
+ final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
+ runThenWaitForBroadcasts(userId, () -> {
+ switchUser(userId);
+ }, Intent.ACTION_MEDIA_MOUNTED);
+
+ waitCoolDownPeriod();
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> {
+ runThenWaitForBroadcasts(userId, () -> {
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ mAm.switchUser(startUser);
+ }, Intent.ACTION_USER_STOPPED);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ }, null);
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests creating a new profile. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileCreate() throws RemoteException {
@@ -596,6 +690,24 @@
}
}
+ /** Tests creating a new profile. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileCreate_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ Log.d(TAG, "Starting timer");
+ final int userId = createManagedProfile();
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests starting (unlocking) an uninitialized profile. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock() throws RemoteException {
@@ -616,6 +728,27 @@
}
}
+ /** Tests starting (unlocking) an uninitialized profile. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileUnlock_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int userId = createManagedProfile();
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ startUserInBackgroundAndWaitForUnlock(userId);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests starting (unlocking) a previously-started, but no-longer-running, profile. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock_stopped() throws RemoteException {
@@ -639,6 +772,29 @@
}
}
+ /** Tests starting (unlocking) a previously-started, but no-longer-running, profile. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileUnlock_stopped_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+ final int userId = createManagedProfile();
+ // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
+ startUserInBackgroundAndWaitForUnlock(userId);
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ stopUserAfterWaitingForBroadcastIdle(userId, true);
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ startUserInBackgroundAndWaitForUnlock(userId);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ removeUser(userId);
+ }
+
/**
* Tests starting (unlocking) & launching an already-installed app in an uninitialized profile.
*/
@@ -665,6 +821,32 @@
}
/**
+ * Tests starting (unlocking) & launching an already-installed app in an uninitialized profile.
+ */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileUnlockAndLaunchApp_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int userId = createManagedProfile();
+ WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
+ installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ startUserInBackgroundAndWaitForUnlock(userId);
+ startApp(userId, DUMMY_PACKAGE_NAME);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
+ /**
* Tests starting (unlocking) and launching a previously-launched app
* in a previously-started, but no-longer-running, profile.
* A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
@@ -696,6 +878,39 @@
}
}
+ /**
+ * Tests starting (unlocking) and launching a previously-launched app
+ * in a previously-started, but no-longer-running, profile.
+ * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
+ * {@link #managedProfileUnlock_stopped}}.
+ */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileUnlockAndLaunchApp_stopped_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int userId = createManagedProfile();
+ WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
+ installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
+ startUserInBackgroundAndWaitForUnlock(userId);
+ startApp(userId, DUMMY_PACKAGE_NAME);
+ stopUserAfterWaitingForBroadcastIdle(userId, true);
+ SystemClock.sleep(1_000); // 1 second cool-down before re-starting profile.
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ startUserInBackgroundAndWaitForUnlock(userId);
+ startApp(userId, DUMMY_PACKAGE_NAME);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests installing a pre-existing app in an uninitialized profile. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileInstall() throws RemoteException {
@@ -716,6 +931,27 @@
}
}
+ /** Tests installing a pre-existing app in an uninitialized profile. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileInstall_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int userId = createManagedProfile();
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/**
* Tests creating a new profile, starting (unlocking) it, installing an app,
* and launching that app in it.
@@ -742,6 +978,33 @@
}
}
+ /**
+ * Tests creating a new profile, starting (unlocking) it, installing an app,
+ * and launching that app in it.
+ */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileCreateUnlockInstallAndLaunchApp_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ final int userId = createManagedProfile();
+ startUserInBackgroundAndWaitForUnlock(userId);
+ installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
+ startApp(userId, DUMMY_PACKAGE_NAME);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ removeUser(userId);
+ waitCoolDownPeriod();
+ mRunner.resumeTimingForNextIteration();
+ }
+ }
+
/** Tests stopping a profile. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileStopped() throws RemoteException {
@@ -766,6 +1029,30 @@
}
}
+ /** Tests stopping a profile. */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void managedProfileStopped_realistic() throws RemoteException {
+ assumeTrue(mHasManagedUserFeature);
+ final int userId = createManagedProfile();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+
+ runThenWaitForBroadcasts(userId, () -> {
+ startUserInBackgroundAndWaitForUnlock(userId);
+ }, Intent.ACTION_MEDIA_MOUNTED);
+ waitCoolDownPeriod();
+ mRunner.resumeTiming();
+ Log.d(TAG, "Starting timer");
+
+ stopUser(userId, true);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ mRunner.resumeTimingForNextIteration();
+ }
+ removeUser(userId);
+ }
+
// TODO: This is just a POC. Do this properly and add more.
/** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 4a3a6d9..95d6f850 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -16,11 +16,15 @@
package android.app.tare;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Provides access to the resource economy service.
*
@@ -91,10 +95,38 @@
}
}
- public static final String KEY_ENABLE_TARE = "enable_tare";
+
+ public static final int ENABLED_MODE_OFF = 0;
+ public static final int ENABLED_MODE_ON = 1;
+ /**
+ * Go through the motions, tracking events, updating balances and other TARE state values,
+ * but don't use TARE to affect actual device behavior.
+ */
+ public static final int ENABLED_MODE_SHADOW = 2;
+
+ /** @hide */
+ @IntDef(prefix = {"ENABLED_MODE_"}, value = {
+ ENABLED_MODE_OFF,
+ ENABLED_MODE_ON,
+ ENABLED_MODE_SHADOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EnabledMode {
+ }
+
+ public static String enabledModeToString(@EnabledMode int mode) {
+ switch (mode) {
+ case ENABLED_MODE_OFF: return "ENABLED_MODE_OFF";
+ case ENABLED_MODE_ON: return "ENABLED_MODE_ON";
+ case ENABLED_MODE_SHADOW: return "ENABLED_MODE_SHADOW";
+ default: return "ENABLED_MODE_" + mode;
+ }
+ }
+
+ public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode";
public static final String KEY_ENABLE_POLICY_ALARM = "enable_policy_alarm";
public static final String KEY_ENABLE_POLICY_JOB_SCHEDULER = "enable_policy_job";
- public static final boolean DEFAULT_ENABLE_TARE = true;
+ public static final int DEFAULT_ENABLE_TARE_MODE = ENABLED_MODE_ON;
public static final boolean DEFAULT_ENABLE_POLICY_ALARM = true;
public static final boolean DEFAULT_ENABLE_POLICY_JOB_SCHEDULER = true;
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index fab5b5f..ad406a1 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -158,17 +158,11 @@
boolean mForceAllAppStandbyForSmallBattery;
/**
- * True if the forced app standby feature is enabled in settings
- */
- @GuardedBy("mLock")
- boolean mForcedAppStandbyEnabled;
-
- /**
* A lock-free set of (uid, packageName) pairs in background restricted mode.
*
* <p>
- * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
- * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write.
+ * It's basically shadowing the {@link #mRunAnyRestrictedPackages}, any mutations on it would
+ * result in copy-on-write.
* </p>
*/
volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();
@@ -200,10 +194,9 @@
int TEMP_EXEMPTION_LIST_CHANGED = 5;
int EXEMPTED_BUCKET_CHANGED = 6;
int FORCE_ALL_CHANGED = 7;
- int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
- int IS_UID_ACTIVE_CACHED = 9;
- int IS_UID_ACTIVE_RAW = 10;
+ int IS_UID_ACTIVE_CACHED = 8;
+ int IS_UID_ACTIVE_RAW = 9;
}
private final StatLogger mStatLogger = new StatLogger(new String[] {
@@ -215,7 +208,6 @@
"TEMP_EXEMPTION_LIST_CHANGED",
"EXEMPTED_BUCKET_CHANGED",
"FORCE_ALL_CHANGED",
- "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
"IS_UID_ACTIVE_CACHED",
"IS_UID_ACTIVE_RAW",
@@ -228,18 +220,10 @@
}
void register() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
- false, this);
-
mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
}
- boolean isForcedAppStandbyEnabled() {
- return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
- }
-
boolean isForcedAppStandbyForSmallBatteryEnabled() {
return injectGetGlobalSettingInt(
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
@@ -247,21 +231,7 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
- final boolean enabled = isForcedAppStandbyEnabled();
- synchronized (mLock) {
- if (mForcedAppStandbyEnabled == enabled) {
- return;
- }
- mForcedAppStandbyEnabled = enabled;
- updateBackgroundRestrictedUidPackagesLocked();
- if (DEBUG) {
- Slog.d(TAG, "Forced app standby feature flag changed: "
- + mForcedAppStandbyEnabled);
- }
- }
- mHandler.notifyForcedAppStandbyFeatureFlagChanged();
- } else if (Settings.Global.getUriFor(
+ if (Settings.Global.getUriFor(
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
synchronized (mLock) {
@@ -515,7 +485,6 @@
mFlagsObserver = new FeatureFlagsObserver();
mFlagsObserver.register();
- mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
mForceAllAppStandbyForSmallBattery =
mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
mStandbyTracker = new StandbyTracker();
@@ -636,14 +605,10 @@
/**
* Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
- * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}.
+ * {@link #mRunAnyRestrictedPackages}.
*/
@GuardedBy("mLock")
private void updateBackgroundRestrictedUidPackagesLocked() {
- if (!mForcedAppStandbyEnabled) {
- mBackgroundRestrictedUidPackages = Collections.emptySet();
- return;
- }
Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
@@ -821,13 +786,14 @@
private class MyHandler extends Handler {
private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
+ // Unused ids 1, 2.
private static final int MSG_RUN_ANY_CHANGED = 3;
private static final int MSG_ALL_UNEXEMPTED = 4;
private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
private static final int MSG_FORCE_ALL_CHANGED = 7;
private static final int MSG_USER_REMOVED = 8;
- private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
+ // Unused id 9.
private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;
@@ -867,11 +833,6 @@
obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
}
- public void notifyForcedAppStandbyFeatureFlagChanged() {
- removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
- obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
- }
-
public void notifyExemptedBucketChanged() {
removeMessages(MSG_EXEMPTED_BUCKET_CHANGED);
obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
@@ -966,22 +927,6 @@
mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
return;
- case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
- // Feature flag for forced app standby changed.
- final boolean unblockAlarms;
- synchronized (mLock) {
- unblockAlarms = !mForcedAppStandbyEnabled;
- }
- for (Listener l : cloneListeners()) {
- l.updateAllJobs();
- if (unblockAlarms) {
- l.unblockAllUnrestrictedAlarms();
- }
- }
- mStatLogger.logDurationStat(
- Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start);
- return;
-
case MSG_USER_REMOVED:
handleUserRemoved(msg.arg1);
return;
@@ -1164,8 +1109,7 @@
// If apps will be put into restricted standby bucket automatically on user-forced
// app standby, instead of blocking alarms completely, let the restricted standby bucket
// policy take care of it.
- return (mForcedAppStandbyEnabled
- && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+ return (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
&& isRunAnyRestrictedLocked(uid, packageName));
}
}
@@ -1210,8 +1154,7 @@
// If apps will be put into restricted standby bucket automatically on user-forced
// app standby, instead of blocking jobs completely, let the restricted standby bucket
// policy take care of it.
- if (mForcedAppStandbyEnabled
- && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+ if (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
&& isRunAnyRestrictedLocked(uid, packageName)) {
return true;
}
@@ -1321,8 +1264,6 @@
pw.println("Current AppStateTracker State:");
pw.increaseIndent();
- pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
-
pw.print("Force all apps standby: ");
pw.println(isForceAllAppsStandbyEnabled());
@@ -1400,8 +1341,6 @@
synchronized (mLock) {
final long token = proto.start(fieldId);
- proto.write(AppStateTrackerProto.FORCED_APP_STANDBY_FEATURE_ENABLED,
- mForcedAppStandbyEnabled);
proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
isForceAllAppsStandbyEnabled());
proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e41eb00..2533a0f 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -77,6 +77,7 @@
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
+import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -852,7 +853,7 @@
public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
- public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
+ public int USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE;
/**
* The amount of temporary reserve quota to give apps on receiving the
@@ -892,7 +893,7 @@
AlarmManagerEconomicPolicy.POLICY_ALARM);
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ALARM_MANAGER));
updateTareSettings(
- economyManagerInternal.isEnabled(AlarmManagerEconomicPolicy.POLICY_ALARM));
+ economyManagerInternal.getEnabledMode(AlarmManagerEconomicPolicy.POLICY_ALARM));
}
public void updateAllowWhileIdleWhitelistDurationLocked() {
@@ -1065,18 +1066,19 @@
}
@Override
- public void onTareEnabledStateChanged(boolean isTareEnabled) {
- updateTareSettings(isTareEnabled);
+ public void onTareEnabledModeChanged(@EconomyManager.EnabledMode int enabledMode) {
+ updateTareSettings(enabledMode);
}
- private void updateTareSettings(boolean isTareEnabled) {
+ private void updateTareSettings(int enabledMode) {
synchronized (mLock) {
- if (USE_TARE_POLICY != isTareEnabled) {
- USE_TARE_POLICY = isTareEnabled;
+ if (USE_TARE_POLICY != enabledMode) {
+ USE_TARE_POLICY = enabledMode;
final boolean changed = mAlarmStore.updateAlarmDeliveries(alarm -> {
final boolean standbyChanged = adjustDeliveryTimeBasedOnBucketLocked(alarm);
final boolean tareChanged = adjustDeliveryTimeBasedOnTareLocked(alarm);
- if (USE_TARE_POLICY) {
+ if (USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
+ // Only register listeners if we're going to be acting on the policy.
registerTareListener(alarm);
} else {
mEconomyManagerInternal.unregisterAffordabilityChangeListener(
@@ -1086,7 +1088,7 @@
}
return standbyChanged || tareChanged;
});
- if (!USE_TARE_POLICY) {
+ if (USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
// Remove the cached values so we don't accidentally use them when TARE is
// re-enabled.
mAffordabilityCache.clear();
@@ -2526,7 +2528,8 @@
*/
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
final long nowElapsed = mInjector.getElapsedRealtimeMillis();
- if (mConstants.USE_TARE_POLICY || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
+ if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON
+ || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
@@ -2586,7 +2589,7 @@
*/
private boolean adjustDeliveryTimeBasedOnTareLocked(Alarm alarm) {
final long nowElapsed = mInjector.getElapsedRealtimeMillis();
- if (!mConstants.USE_TARE_POLICY
+ if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON
|| isExemptFromTare(alarm) || hasEnoughWealthLocked(alarm)) {
return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed);
}
@@ -2596,7 +2599,8 @@
}
private void registerTareListener(Alarm alarm) {
- if (!mConstants.USE_TARE_POLICY) {
+ if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
+ // Only register listeners if we're going to be acting on the policy.
return;
}
mEconomyManagerInternal.registerAffordabilityChangeListener(
@@ -2607,7 +2611,7 @@
/** Unregister the TARE listener associated with the alarm if it's no longer needed. */
@GuardedBy("mLock")
private void maybeUnregisterTareListenerLocked(Alarm alarm) {
- if (!mConstants.USE_TARE_POLICY) {
+ if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
return;
}
final EconomyManagerInternal.ActionBill bill = TareBill.getAppropriateBill(alarm);
@@ -3126,7 +3130,7 @@
mConstants.dump(pw);
pw.println();
- if (mConstants.USE_TARE_POLICY) {
+ if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
pw.println("TARE details:");
pw.increaseIndent();
@@ -4500,7 +4504,8 @@
}
private void reportAlarmEventToTare(Alarm alarm) {
- if (!mConstants.USE_TARE_POLICY) {
+ // Don't bother reporting events if TARE is completely off.
+ if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_OFF) {
return;
}
final boolean allowWhileIdle =
@@ -4805,7 +4810,7 @@
if (a.wakeup) {
wakeupUids.add(a.uid);
}
- if (mConstants.USE_TARE_POLICY) {
+ if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
if (!isExemptFromTare(a)) {
triggerPackages.add(UserPackage.of(
UserHandle.getUserId(a.creatorUid),
@@ -4823,7 +4828,7 @@
}
deliverAlarmsLocked(triggerList, nowELAPSED);
mTemporaryQuotaReserve.cleanUpExpiredQuotas(nowELAPSED);
- if (mConstants.USE_TARE_POLICY) {
+ if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
reorderAlarmsBasedOnTare(triggerPackages);
} else {
reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
@@ -5379,9 +5384,7 @@
@Override
public void unblockAllUnrestrictedAlarms() {
- // Called when:
- // 1. Power exemption list changes,
- // 2. User FAS feature is disabled.
+ // Called when the power exemption list changes.
synchronized (mLock) {
sendAllUnrestrictedPendingBackgroundAlarmsLocked();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 43f7279..ccad436 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -43,6 +43,7 @@
import android.app.job.JobSnapshot;
import android.app.job.JobWorkItem;
import android.app.job.UserVisibleJobSummary;
+import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -417,7 +418,8 @@
// Load all the constants.
synchronized (mLock) {
mConstants.updateTareSettingsLocked(
- economyManagerInternal.isEnabled(JobSchedulerEconomicPolicy.POLICY_JOB));
+ economyManagerInternal.getEnabledMode(
+ JobSchedulerEconomicPolicy.POLICY_JOB));
}
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
}
@@ -514,8 +516,8 @@
}
@Override
- public void onTareEnabledStateChanged(boolean isTareEnabled) {
- if (mConstants.updateTareSettingsLocked(isTareEnabled)) {
+ public void onTareEnabledModeChanged(@EconomyManager.EnabledMode int enabledMode) {
+ if (mConstants.updateTareSettingsLocked(enabledMode)) {
for (int controller = 0; controller < mControllers.size(); controller++) {
final StateController sc = mControllers.get(controller);
sc.onConstantsUpdatedLocked();
@@ -962,10 +964,11 @@
DEFAULT_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS)));
}
- private boolean updateTareSettingsLocked(boolean isTareEnabled) {
+ private boolean updateTareSettingsLocked(@EconomyManager.EnabledMode int enabledMode) {
boolean changed = false;
- if (USE_TARE_POLICY != isTareEnabled) {
- USE_TARE_POLICY = isTareEnabled;
+ final boolean useTare = enabledMode == EconomyManager.ENABLED_MODE_ON;
+ if (USE_TARE_POLICY != useTare) {
+ USE_TARE_POLICY = useTare;
changed = true;
}
return changed;
@@ -2545,6 +2548,7 @@
final JobStatus rescheduledJob = needsReschedule
? getRescheduleJobForFailureLocked(jobStatus, debugStopReason) : null;
if (rescheduledJob != null
+ && !rescheduledJob.shouldTreatAsUserInitiatedJob()
&& (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
|| debugStopReason == JobParameters.INTERNAL_STOP_REASON_PREEMPT)) {
rescheduledJob.disallowRunInBatterySaverAndDoze();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index fb5d63e..c2168d2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -361,7 +361,14 @@
boolean binding = false;
try {
final int bindFlags;
- if (job.shouldTreatAsExpeditedJob()) {
+ if (job.shouldTreatAsUserInitiatedJob()) {
+ // TODO (191785864, 261999509): add an appropriate flag so user-initiated jobs
+ // can bypass data saver
+ bindFlags = Context.BIND_AUTO_CREATE
+ | Context.BIND_ALMOST_PERCEPTIBLE
+ | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
+ | Context.BIND_NOT_APP_COMPONENT_USAGE;
+ } else if (job.shouldTreatAsExpeditedJob()) {
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALMOST_PERCEPTIBLE
| Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 16f5c7f..b87dec1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -98,6 +98,13 @@
~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY
| ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER
| ConnectivityManager.BLOCKED_REASON_DOZE);
+ // TODO(261999509): allow bypassing data saver & user-restricted. However, when we allow a UI
+ // job to run while data saver restricts the app, we must ensure that we don't run regular
+ // jobs when we put a hole in the data saver wall for the UI job
+ private static final int UNBYPASSABLE_UI_BLOCKED_REASONS =
+ ~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY
+ | ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER
+ | ConnectivityManager.BLOCKED_REASON_DOZE);
private static final int UNBYPASSABLE_FOREGROUND_BLOCKED_REASONS =
~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY
| ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER
@@ -1080,6 +1087,11 @@
Slog.d(TAG, "Using FG bypass for " + jobStatus.getSourceUid());
}
unbypassableBlockedReasons = UNBYPASSABLE_FOREGROUND_BLOCKED_REASONS;
+ } else if (jobStatus.shouldTreatAsUserInitiatedJob()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Using UI bypass for " + jobStatus.getSourceUid());
+ }
+ unbypassableBlockedReasons = UNBYPASSABLE_UI_BLOCKED_REASONS;
} else if (jobStatus.shouldTreatAsExpeditedJob() || jobStatus.startedAsExpeditedJob) {
if (DEBUG) {
Slog.d(TAG, "Using EJ bypass for " + jobStatus.getSourceUid());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index a2e8eb4..9a69fdf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1411,16 +1411,18 @@
public boolean canRunInDoze() {
return appHasDozeExemption
|| (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0
- || ((shouldTreatAsExpeditedJob() || startedAsExpeditedJob)
|| shouldTreatAsUserInitiatedJob()
- && (mDynamicConstraints & CONSTRAINT_DEVICE_NOT_DOZING) == 0);
+ // EJs can't run in Doze if we explicitly require that the device is not Dozing.
+ || ((shouldTreatAsExpeditedJob() || startedAsExpeditedJob)
+ && (mDynamicConstraints & CONSTRAINT_DEVICE_NOT_DOZING) == 0);
}
boolean canRunInBatterySaver() {
return (getInternalFlags() & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0
- || ((shouldTreatAsExpeditedJob() || startedAsExpeditedJob)
|| shouldTreatAsUserInitiatedJob()
- && (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
+ // EJs can't run in Battery Saver if we explicitly require that Battery Saver is off
+ || ((shouldTreatAsExpeditedJob() || startedAsExpeditedJob)
+ && (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
}
/** @return true if the constraint was changed, false otherwise. */
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 2b59209..dcc324d 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -16,6 +16,7 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.server.tare.EconomicPolicy.REGULATION_BASIC_INCOME;
@@ -1111,7 +1112,7 @@
final ActionAffordabilityNote note =
new ActionAffordabilityNote(bill, listener, economicPolicy);
if (actionAffordabilityNotes.add(note)) {
- if (!mIrs.isEnabled()) {
+ if (mIrs.getEnabledMode() == ENABLED_MODE_OFF) {
// When TARE isn't enabled, we always say something is affordable. We also don't
// want to silently drop affordability change listeners in case TARE becomes enabled
// because then clients will be in an ambiguous state.
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
index 716769c..5b305ad 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.tare.EconomyManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -121,7 +122,7 @@
/** Listener for various TARE state changes. */
interface TareStateChangeListener {
- void onTareEnabledStateChanged(boolean isTareEnabled);
+ void onTareEnabledModeChanged(@EconomyManager.EnabledMode int tareEnabledMode);
}
/**
@@ -135,11 +136,13 @@
*/
long getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
- /** Returns true if TARE is enabled. */
- boolean isEnabled();
+ /** Returns the current TARE enabled mode. */
+ @EconomyManager.EnabledMode
+ int getEnabledMode();
- /** Returns true if TARE and the specified policy are enabled. */
- boolean isEnabled(@EconomicPolicy.Policy int policyId);
+ /** Returns the current TARE enabled mode for the specified policy. */
+ @EconomyManager.EnabledMode
+ int getEnabledMode(@EconomicPolicy.Policy int policyId);
/**
* Register an {@link AffordabilityChangeListener} to track when an app's ability to afford the
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 08c1a0c..caf72e8 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -16,6 +16,10 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
+import static android.app.tare.EconomyManager.ENABLED_MODE_ON;
+import static android.app.tare.EconomyManager.ENABLED_MODE_SHADOW;
+import static android.app.tare.EconomyManager.enabledModeToString;
import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -202,7 +206,8 @@
private final SparseArrayMap<String, ArraySet<String>> mInstallers = new SparseArrayMap<>();
private volatile boolean mHasBattery = true;
- private volatile boolean mIsEnabled;
+ @EconomyManager.EnabledMode
+ private volatile int mEnabledMode;
private volatile int mBootPhase;
private volatile boolean mExemptListLoaded;
// In the range [0,100] to represent 0% to 100% battery.
@@ -474,13 +479,20 @@
}
}
- boolean isEnabled() {
- return mIsEnabled;
+ @EconomyManager.EnabledMode
+ int getEnabledMode() {
+ return mEnabledMode;
}
- boolean isEnabled(int policyId) {
+ @EconomyManager.EnabledMode
+ int getEnabledMode(int policyId) {
synchronized (mLock) {
- return isEnabled() && mCompleteEconomicPolicy.isPolicyEnabled(policyId);
+ // For now, treat enabled policies as using the same enabled mode as full TARE.
+ // TODO: have enabled mode by policy
+ if (mCompleteEconomicPolicy.isPolicyEnabled(policyId)) {
+ return mEnabledMode;
+ }
+ return ENABLED_MODE_OFF;
}
}
@@ -857,7 +869,7 @@
@GuardedBy("mLock")
private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return;
}
final String pkgName = event.getPackageName();
@@ -1028,7 +1040,7 @@
/** Perform long-running and/or heavy setup work. This should be called off the main thread. */
private void setupHeavyWork() {
- if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || !mIsEnabled) {
+ if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1079,7 +1091,7 @@
}
private void onBootPhaseSystemServicesReady() {
- if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || !mIsEnabled) {
+ if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || mEnabledMode == ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1101,14 +1113,14 @@
}
private void onBootPhaseThirdPartyAppsCanStart() {
- if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || !mIsEnabled) {
+ if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
return;
}
mHandler.post(this::setupHeavyWork);
}
private void onBootPhaseBootCompleted() {
- if (mBootPhase < PHASE_BOOT_COMPLETED || !mIsEnabled) {
+ if (mBootPhase < PHASE_BOOT_COMPLETED || mEnabledMode == ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1124,7 +1136,7 @@
}
private void setupEverything() {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return;
}
if (mBootPhase >= PHASE_SYSTEM_SERVICES_READY) {
@@ -1139,7 +1151,7 @@
}
private void tearDownEverything() {
- if (mIsEnabled) {
+ if (mEnabledMode != ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1231,7 +1243,7 @@
case MSG_NOTIFY_STATE_CHANGE_LISTENER: {
final int policy = msg.arg1;
final TareStateChangeListener listener = (TareStateChangeListener) msg.obj;
- listener.onTareEnabledStateChanged(isEnabled(policy));
+ listener.onTareEnabledModeChanged(getEnabledMode(policy));
}
break;
@@ -1246,10 +1258,10 @@
}
final ArraySet<TareStateChangeListener> listeners =
mStateChangeListeners.get(policy);
- final boolean isEnabled = isEnabled(policy);
+ final int enabledMode = getEnabledMode(policy);
for (int p = listeners.size() - 1; p >= 0; --p) {
final TareStateChangeListener listener = listeners.valueAt(p);
- listener.onTareEnabledStateChanged(isEnabled);
+ listener.onTareEnabledModeChanged(enabledMode);
}
}
}
@@ -1382,7 +1394,7 @@
@Override
public boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return true;
}
if (isVip(userId, pkgName)) {
@@ -1410,7 +1422,7 @@
@Override
public long getMaxDurationMs(int userId, @NonNull String pkgName,
@NonNull ActionBill bill) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return FOREVER_MS;
}
if (isVip(userId, pkgName)) {
@@ -1437,19 +1449,19 @@
}
@Override
- public boolean isEnabled() {
- return mIsEnabled;
+ public int getEnabledMode() {
+ return mEnabledMode;
}
@Override
- public boolean isEnabled(int policyId) {
- return InternalResourceService.this.isEnabled(policyId);
+ public int getEnabledMode(int policyId) {
+ return InternalResourceService.this.getEnabledMode(policyId);
}
@Override
public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1460,7 +1472,7 @@
@Override
public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return;
}
synchronized (mLock) {
@@ -1472,7 +1484,7 @@
@Override
public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
- if (!mIsEnabled) {
+ if (mEnabledMode == ENABLED_MODE_OFF) {
return;
}
final long nowElapsed = SystemClock.elapsedRealtime();
@@ -1540,7 +1552,7 @@
continue;
}
switch (name) {
- case EconomyManager.KEY_ENABLE_TARE:
+ case EconomyManager.KEY_ENABLE_TARE_MODE:
updateEnabledStatus();
break;
case KEY_ENABLE_TIP3:
@@ -1567,17 +1579,33 @@
private void updateEnabledStatus() {
// User setting should override DeviceConfig setting.
- final boolean isTareEnabledDC = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TARE,
- EconomyManager.KEY_ENABLE_TARE, EconomyManager.DEFAULT_ENABLE_TARE);
- final boolean isTareEnabled = isTareSupported()
- && Settings.Global.getInt(mContentResolver,
- Settings.Global.ENABLE_TARE, isTareEnabledDC ? 1 : 0) == 1;
- if (mIsEnabled != isTareEnabled) {
- mIsEnabled = isTareEnabled;
- if (mIsEnabled) {
- setupEverything();
- } else {
- tearDownEverything();
+ final int tareEnabledModeDC = DeviceConfig.getInt(DeviceConfig.NAMESPACE_TARE,
+ EconomyManager.KEY_ENABLE_TARE_MODE, EconomyManager.DEFAULT_ENABLE_TARE_MODE);
+ final int tareEnabledModeConfig = isTareSupported()
+ ? Settings.Global.getInt(mContentResolver,
+ Settings.Global.ENABLE_TARE, tareEnabledModeDC)
+ : ENABLED_MODE_OFF;
+ final int enabledMode;
+ if (tareEnabledModeConfig == ENABLED_MODE_OFF
+ || tareEnabledModeConfig == ENABLED_MODE_ON
+ || tareEnabledModeConfig == ENABLED_MODE_SHADOW) {
+ // Config has a valid enabled mode.
+ enabledMode = tareEnabledModeConfig;
+ } else {
+ enabledMode = EconomyManager.DEFAULT_ENABLE_TARE_MODE;
+ }
+ if (mEnabledMode != enabledMode) {
+ // A full change where we've gone from OFF to {SHADOW or ON}, or vie versa.
+ // With this transition, we'll have to set up or tear down.
+ final boolean fullEnableChange =
+ mEnabledMode == ENABLED_MODE_OFF || enabledMode == ENABLED_MODE_OFF;
+ mEnabledMode = enabledMode;
+ if (fullEnableChange) {
+ if (mEnabledMode != ENABLED_MODE_OFF) {
+ setupEverything();
+ } else {
+ tearDownEverything();
+ }
}
mHandler.obtainMessage(
MSG_NOTIFY_STATE_CHANGE_LISTENERS, EconomicPolicy.ALL_POLICIES, 0)
@@ -1592,7 +1620,8 @@
final int oldEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
mCompleteEconomicPolicy.tearDown();
mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
- if (mIsEnabled && mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
+ if (mEnabledMode != ENABLED_MODE_OFF
+ && mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
mCompleteEconomicPolicy.setup(getAllDeviceConfigProperties());
if (minLimit != mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
|| maxLimit
@@ -1626,7 +1655,7 @@
}
}
mVipOverrides.clear();
- if (mIsEnabled) {
+ if (mEnabledMode != ENABLED_MODE_OFF) {
mAgent.onVipStatusChangedLocked(changedPkgs);
}
}
@@ -1645,7 +1674,7 @@
mVipOverrides.add(userId, pkgName, newVipState);
}
changed = isVip(userId, pkgName) != wasVip;
- if (mIsEnabled && changed) {
+ if (mEnabledMode != ENABLED_MODE_OFF && changed) {
mAgent.onVipStatusChangedLocked(userId, pkgName);
}
}
@@ -1668,8 +1697,8 @@
return;
}
synchronized (mLock) {
- pw.print("Is enabled: ");
- pw.println(mIsEnabled);
+ pw.print("Enabled mode: ");
+ pw.println(enabledModeToString(mEnabledMode));
pw.print("Current battery level: ");
pw.println(mCurrentBatteryLevel);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 66327fd..08439f3 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -16,6 +16,7 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static com.android.server.tare.TareUtils.appToString;
@@ -662,7 +663,7 @@
// Remove mCleanRunnable callbacks since we're going to clean up the ledgers before
// writing anyway.
TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
- if (!mIrs.isEnabled()) {
+ if (mIrs.getEnabledMode() == ENABLED_MODE_OFF) {
// If it's no longer enabled, we would have cleared all the data in memory and would
// accidentally write an empty file, thus deleting all the history.
return;
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 13a2a94..9909764 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -965,17 +965,21 @@
Slog.d(TAG, " Checking idle state for " + packageName
+ " minBucket=" + standbyBucketToString(minBucket));
}
+ final boolean previouslyIdle, stillIdle;
if (minBucket <= STANDBY_BUCKET_ACTIVE) {
// No extra processing needed for ACTIVE or higher since apps can't drop into lower
// buckets.
synchronized (mAppIdleLock) {
+ previouslyIdle = mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
minBucket, REASON_MAIN_DEFAULT);
+ stillIdle = mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
}
maybeInformListeners(packageName, userId, elapsedRealtime,
minBucket, REASON_MAIN_DEFAULT, false);
} else {
synchronized (mAppIdleLock) {
+ previouslyIdle = mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
final AppIdleHistory.AppUsageHistory app =
mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
@@ -1073,11 +1077,17 @@
if (oldBucket != newBucket || predictionLate) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
elapsedRealtime, newBucket, reason);
+ stillIdle = mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
maybeInformListeners(packageName, userId, elapsedRealtime,
newBucket, reason, false);
+ } else {
+ stillIdle = previouslyIdle;
}
}
}
+ if (previouslyIdle != stillIdle) {
+ notifyBatteryStats(packageName, userId, stillIdle);
+ }
}
/** Returns true if there hasn't been a prediction for the app in a while. */
@@ -1234,8 +1244,9 @@
appHistory.currentBucket, reason, userStartedInteracting);
}
- if (previouslyIdle) {
- notifyBatteryStats(pkg, userId, false);
+ final boolean stillIdle = appHistory.currentBucket >= AppIdleHistory.IDLE_BUCKET_CUTOFF;
+ if (previouslyIdle != stillIdle) {
+ notifyBatteryStats(pkg, userId, stillIdle);
}
}
@@ -1808,8 +1819,14 @@
reason = REASON_MAIN_FORCED_BY_SYSTEM
| (app.bucketingReason & REASON_SUB_MASK)
| (reason & REASON_SUB_MASK);
+ final boolean previouslyIdle =
+ app.currentBucket >= AppIdleHistory.IDLE_BUCKET_CUTOFF;
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
newBucket, reason, resetTimeout);
+ final boolean stillIdle = newBucket >= AppIdleHistory.IDLE_BUCKET_CUTOFF;
+ if (previouslyIdle != stillIdle) {
+ notifyBatteryStats(packageName, userId, stillIdle);
+ }
return;
}
@@ -1910,8 +1927,13 @@
// Make sure we don't put the app in a lower bucket than it's supposed to be in.
newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId));
+ final boolean previouslyIdle = app.currentBucket >= AppIdleHistory.IDLE_BUCKET_CUTOFF;
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
reason, resetTimeout);
+ final boolean stillIdle = newBucket >= AppIdleHistory.IDLE_BUCKET_CUTOFF;
+ if (previouslyIdle != stillIdle) {
+ notifyBatteryStats(packageName, userId, stillIdle);
+ }
}
maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
}
@@ -2668,7 +2690,9 @@
}
void noteEvent(int event, String packageName, int uid) throws RemoteException {
- mBatteryStats.noteEvent(event, packageName, uid);
+ if (mBatteryStats != null) {
+ mBatteryStats.noteEvent(event, packageName, uid);
+ }
}
PackageManagerInternal getPackageManagerInternal() {
diff --git a/core/api/current.txt b/core/api/current.txt
index c811a09..978713a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1488,6 +1488,7 @@
field public static final int strokeLineJoin = 16843788; // 0x101040c
field public static final int strokeMiterLimit = 16843789; // 0x101040d
field public static final int strokeWidth = 16843783; // 0x1010407
+ field public static final int stylusHandwritingSettingsActivity;
field public static final int subMenuArrow = 16844019; // 0x10104f3
field public static final int submitBackground = 16843912; // 0x1010488
field public static final int subtitle = 16843473; // 0x10102d1
@@ -4318,6 +4319,7 @@
method public void recreate();
method public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
method public void registerForContextMenu(android.view.View);
+ method @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_CAPTURE) public void registerScreenCaptureCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.Activity.ScreenCaptureCallback);
method public boolean releaseInstance();
method @Deprecated public final void removeDialog(int);
method public void reportFullyDrawn();
@@ -4403,6 +4405,7 @@
method public void triggerSearch(String, @Nullable android.os.Bundle);
method public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
method public void unregisterForContextMenu(android.view.View);
+ method @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_CAPTURE) public void unregisterScreenCaptureCallback(@NonNull android.app.Activity.ScreenCaptureCallback);
field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1
field public static final int DEFAULT_KEYS_DISABLE = 0; // 0x0
field public static final int DEFAULT_KEYS_SEARCH_GLOBAL = 4; // 0x4
@@ -4416,6 +4419,10 @@
field public static final int RESULT_OK = -1; // 0xffffffff
}
+ public static interface Activity.ScreenCaptureCallback {
+ method public void onScreenCaptured();
+ }
+
@Deprecated public class ActivityGroup extends android.app.Activity {
ctor @Deprecated public ActivityGroup();
ctor @Deprecated public ActivityGroup(boolean);
@@ -7535,6 +7542,7 @@
method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
method @Deprecated @Nullable public String getCertInstallerPackage(@NonNull android.content.ComponentName) throws java.lang.SecurityException;
+ method @Nullable public android.app.admin.PackagePolicy getCredentialManagerPolicy();
method @Deprecated @Nullable public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
method @Deprecated public boolean getCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName);
method @Deprecated public boolean getCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName);
@@ -7687,6 +7695,7 @@
method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
method public void setCommonCriteriaModeEnabled(@NonNull android.content.ComponentName, boolean);
method public void setConfiguredNetworksLockdownState(@NonNull android.content.ComponentName, boolean);
+ method public void setCredentialManagerPolicy(@Nullable android.app.admin.PackagePolicy);
method @Deprecated public void setCrossProfileCalendarPackages(@NonNull android.content.ComponentName, @Nullable java.util.Set<java.lang.String>);
method @Deprecated public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
method @Deprecated public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
@@ -12880,16 +12889,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.SigningInfo> CREATOR;
}
- public final class UserProperties implements android.os.Parcelable {
- method public int describeContents();
- method public int getShowInLauncher();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserProperties> CREATOR;
- field public static final int SHOW_IN_LAUNCHER_NO = 2; // 0x2
- field public static final int SHOW_IN_LAUNCHER_SEPARATE = 1; // 0x1
- field public static final int SHOW_IN_LAUNCHER_WITH_PARENT = 0; // 0x0
- }
-
public final class VersionedPackage implements android.os.Parcelable {
ctor public VersionedPackage(@NonNull String, int);
ctor public VersionedPackage(@NonNull String, long);
@@ -19044,15 +19043,15 @@
method public int getSurfaceGroupId();
method @NonNull public java.util.List<android.view.Surface> getSurfaces();
method public int getTimestampBase();
- method public boolean isReadoutTimestampUsed();
+ method public boolean isReadoutTimestampEnabled();
method public void removeSensorPixelModeUsed(int);
method public void removeSurface(@NonNull android.view.Surface);
method public void setDynamicRangeProfile(long);
method public void setMirrorMode(int);
method public void setPhysicalCameraId(@Nullable String);
+ method public void setReadoutTimestampEnabled(boolean);
method public void setStreamUseCase(long);
method public void setTimestampBase(int);
- method public void useReadoutTimestamp(boolean);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int MIRROR_MODE_AUTO = 0; // 0x0
@@ -20911,6 +20910,7 @@
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
+ method public void adjustVolumeGroupVolume(int, int, int);
method public void clearCommunicationDevice();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public boolean clearPreferredMixerAttributes(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
@@ -20941,6 +20941,7 @@
method public float getStreamVolumeDb(int, int, int);
method @NonNull public java.util.List<android.media.AudioMixerAttributes> getSupportedMixerAttributes(@NonNull android.media.AudioDeviceInfo);
method @Deprecated public int getVibrateSetting(int);
+ method public int getVolumeGroupIdForAttributes(@NonNull android.media.AudioAttributes);
method @Deprecated public boolean isBluetoothA2dpOn();
method public boolean isBluetoothScoAvailableOffCall();
method @Deprecated public boolean isBluetoothScoOn();
@@ -20954,6 +20955,7 @@
method public boolean isStreamMute(int);
method public boolean isSurroundFormatEnabled(int);
method public boolean isVolumeFixed();
+ method public boolean isVolumeGroupMuted(int);
method @Deprecated public boolean isWiredHeadsetOn();
method public void loadSoundEffects();
method public void playSoundEffect(int);
@@ -24035,6 +24037,7 @@
method public void registerTransferCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.TransferCallback);
method public void setOnGetControllerHintsListener(@Nullable android.media.MediaRouter2.OnGetControllerHintsListener);
method public void setRouteListingPreference(@Nullable android.media.RouteListingPreference);
+ method public void showSystemOutputSwitcher();
method public void stop();
method public void transferTo(@NonNull android.media.MediaRoute2Info);
method public void unregisterControllerCallback(@NonNull android.media.MediaRouter2.ControllerCallback);
@@ -33224,7 +33227,6 @@
method public android.os.UserHandle getUserForSerialNumber(long);
method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS", "android.permission.QUERY_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public String getUserName();
method public java.util.List<android.os.UserHandle> getUserProfiles();
- method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.QUERY_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.content.pm.UserProperties getUserProperties(@NonNull android.os.UserHandle);
method public android.os.Bundle getUserRestrictions();
method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(String);
@@ -35375,7 +35377,7 @@
}
public static final class ContactsContract.CommonDataKinds.Email implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String ADDRESS = "data1";
field public static final android.net.Uri CONTENT_FILTER_URI;
@@ -35396,7 +35398,7 @@
}
public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeResource(Integer);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
@@ -35429,7 +35431,7 @@
public static final class ContactsContract.CommonDataKinds.Im implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static CharSequence getProtocolLabel(android.content.res.Resources, int, CharSequence);
method public static int getProtocolLabelResource(int);
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
field public static final String CUSTOM_PROTOCOL = "data6";
@@ -35475,7 +35477,7 @@
}
public static final class ContactsContract.CommonDataKinds.Organization implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String COMPANY = "data1";
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
@@ -35494,7 +35496,7 @@
}
public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
@@ -35541,7 +35543,7 @@
}
public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
@@ -35565,7 +35567,7 @@
}
public static final class ContactsContract.CommonDataKinds.SipAddress implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
@@ -35596,7 +35598,7 @@
}
public static final class ContactsContract.CommonDataKinds.StructuredPostal implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+ method public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method public static int getTypeLabelResource(int);
field public static final String CITY = "data7";
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2";
@@ -44545,6 +44547,7 @@
field public static final int RESULT_SMS_SEND_RETRY_FAILED = 30; // 0x1e
field public static final int RESULT_SYSTEM_ERROR = 15; // 0xf
field public static final int RESULT_UNEXPECTED_EVENT_STOP_SENDING = 28; // 0x1c
+ field public static final int RESULT_USER_NOT_ALLOWED = 33; // 0x21
field public static final int SMS_RP_CAUSE_CALL_BARRING = 10; // 0xa
field public static final int SMS_RP_CAUSE_CONGESTION = 42; // 0x2a
field public static final int SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER = 27; // 0x1b
@@ -52961,10 +52964,10 @@
method public void onRestrictedCaptionAreaChanged(android.graphics.Rect);
}
- public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.view.WindowAnimationFrameStats> CREATOR;
+ @Deprecated public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
+ method @Deprecated public int describeContents();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.view.WindowAnimationFrameStats> CREATOR;
}
public final class WindowContentFrameStats extends android.view.FrameStats implements android.os.Parcelable {
@@ -54927,6 +54930,7 @@
public final class InputMethodInfo implements android.os.Parcelable {
ctor public InputMethodInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
ctor public InputMethodInfo(String, String, CharSequence, String);
+ method @Nullable public android.content.Intent createStylusHandwritingSettingsActivityIntent();
method public int describeContents();
method public void dump(android.util.Printer, String);
method public android.content.ComponentName getComponent();
@@ -54945,6 +54949,7 @@
method public boolean supportsStylusHandwriting();
method public boolean suppressesSpellChecker();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final String ACTION_STYLUS_HANDWRITING_SETTINGS = "android.view.inputmethod.action.STYLUS_HANDWRITING_SETTINGS";
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d3775ad..46ac819 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -329,6 +329,7 @@
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
field public static final String SIGNAL_REBOOT_READINESS = "android.permission.SIGNAL_REBOOT_READINESS";
field public static final String SOUND_TRIGGER_RUN_IN_BATTERY_SAVER = "android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER";
+ field public static final String STAGE_HEALTH_CONNECT_REMOTE_DATA = "android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA";
field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
field public static final String START_CROSS_PROFILE_ACTIVITIES = "android.permission.START_CROSS_PROFILE_ACTIVITIES";
field public static final String START_REVIEW_PERMISSION_DECISIONS = "android.permission.START_REVIEW_PERMISSION_DECISIONS";
@@ -3908,6 +3909,14 @@
method @NonNull public android.content.pm.SuspendDialogInfo.Builder setTitle(@NonNull String);
}
+ public final class UserProperties implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isCredentialShareableWithParent();
+ method public boolean isMediaSharedWithParent();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserProperties> CREATOR;
+ }
+
}
package android.content.pm.dex {
@@ -4588,8 +4597,7 @@
}
public final class HdmiPortInfo implements android.os.Parcelable {
- ctor public HdmiPortInfo(int, int, int, boolean, boolean, boolean);
- ctor public HdmiPortInfo(int, int, int, boolean, boolean, boolean, boolean);
+ ctor @Deprecated public HdmiPortInfo(int, int, int, boolean, boolean, boolean);
method public int describeContents();
method public int getAddress();
method public int getId();
@@ -4604,6 +4612,15 @@
field public static final int PORT_OUTPUT = 1; // 0x1
}
+ public static final class HdmiPortInfo.Builder {
+ ctor public HdmiPortInfo.Builder(int, int, int);
+ method @NonNull public android.hardware.hdmi.HdmiPortInfo build();
+ method @NonNull public android.hardware.hdmi.HdmiPortInfo.Builder setArcSupported(boolean);
+ method @NonNull public android.hardware.hdmi.HdmiPortInfo.Builder setCecSupported(boolean);
+ method @NonNull public android.hardware.hdmi.HdmiPortInfo.Builder setEarcSupported(boolean);
+ method @NonNull public android.hardware.hdmi.HdmiPortInfo.Builder setMhlSupported(boolean);
+ }
+
public abstract class HdmiRecordListener {
ctor public HdmiRecordListener();
method public void onClearTimerRecordingResult(int, int);
@@ -6669,9 +6686,10 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
- method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE", android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
+ method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleVolumeGroupVolume(int);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -6681,6 +6699,9 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMaxVolumeIndex(int);
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMinVolumeIndex(int);
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupVolumeIndex(int);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method public boolean isAudioServerRunning();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isBluetoothVariableLatencyEnabled();
@@ -6708,12 +6729,13 @@
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setDeviceAsNonDefaultForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public void setVolumeGroupVolumeIndex(int, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean supportsBluetoothVariableLatency();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -7120,6 +7142,7 @@
method public int describeContents();
method @NonNull public android.media.AudioAttributes getAudioAttributes();
method public int getId();
+ method @NonNull public String getName();
method public boolean supportsAudioAttributes(@NonNull android.media.AudioAttributes);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR;
@@ -8759,6 +8782,7 @@
field public static final int TYPE_DVBC = 4; // 0x4
field public static final int TYPE_DVBS = 5; // 0x5
field public static final int TYPE_DVBT = 6; // 0x6
+ field public static final int TYPE_IPTV = 11; // 0xb
field public static final int TYPE_ISDBS = 7; // 0x7
field public static final int TYPE_ISDBS3 = 8; // 0x8
field public static final int TYPE_ISDBT = 9; // 0x9
@@ -8781,6 +8805,11 @@
method public int getHierarchy();
method public long getInnerFec();
method @NonNull public int[] getInterleaving();
+ method @IntRange(from=0) public int getIptvAverageJitterMillis();
+ method @NonNull public String getIptvContentUrl();
+ method @IntRange(from=0) public long getIptvPacketsLost();
+ method @IntRange(from=0) public long getIptvPacketsReceived();
+ method @IntRange(from=0) public int getIptvWorstJitterMillis();
method public int getIsdbtMode();
method public int getIsdbtPartialReceptionFlag();
method @IntRange(from=0, to=255) @NonNull public int[] getIsdbtSegment();
@@ -8824,6 +8853,11 @@
field public static final int FRONTEND_STATUS_TYPE_GUARD_INTERVAL = 26; // 0x1a
field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
+ field public static final int FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS = 46; // 0x2e
+ field public static final int FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL = 42; // 0x2a
+ field public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST = 43; // 0x2b
+ field public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED = 44; // 0x2c
+ field public static final int FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS = 45; // 0x2d
field public static final int FRONTEND_STATUS_TYPE_ISDBT_MODE = 37; // 0x25
field public static final int FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG = 38; // 0x26
field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
@@ -8869,6 +8903,60 @@
field public static final int FRONTEND_STATUS_READINESS_UNSUPPORTED = 4; // 0x4
}
+ public class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ ctor public IptvFrontendSettings(@NonNull byte[], @NonNull byte[], int, int, @NonNull android.media.tv.tuner.frontend.IptvFrontendSettingsFec, int, int, long, @NonNull String);
+ method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettings.Builder builder();
+ method @IntRange(from=0) public long getBitrate();
+ method @NonNull public String getContentUrl();
+ method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
+ method public int getDstPort();
+ method @Nullable public android.media.tv.tuner.frontend.IptvFrontendSettingsFec getFec();
+ method public int getIgmp();
+ method public int getProtocol();
+ method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
+ method public int getSrcPort();
+ method public int getType();
+ field public static final int IGMP_UNDEFINED = 0; // 0x0
+ field public static final int IGMP_V1 = 1; // 0x1
+ field public static final int IGMP_V2 = 2; // 0x2
+ field public static final int IGMP_V3 = 4; // 0x4
+ field public static final int PROTOCOL_RTP = 2; // 0x2
+ field public static final int PROTOCOL_UDP = 1; // 0x1
+ field public static final int PROTOCOL_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class IptvFrontendSettings.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setBitrate(@IntRange(from=0) long);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setContentUrl(@NonNull String);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setDstIpAddress(@NonNull byte[]);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setDstPort(int);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setFec(@Nullable android.media.tv.tuner.frontend.IptvFrontendSettingsFec);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setIgmp(int);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setProtocol(int);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcIpAddress(@NonNull byte[]);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcPort(int);
+ }
+
+ public class IptvFrontendSettingsFec {
+ ctor public IptvFrontendSettingsFec(int, int, int);
+ method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder builder();
+ method @IntRange(from=0) public int getFecColNum();
+ method @IntRange(from=0) public int getFecRowNum();
+ method public int getFecType();
+ field public static final int FEC_TYPE_COLUMN = 1; // 0x1
+ field public static final int FEC_TYPE_COLUMN_ROW = 4; // 0x4
+ field public static final int FEC_TYPE_ROW = 2; // 0x2
+ field public static final int FEC_TYPE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class IptvFrontendSettingsFec.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec build();
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecColNum(@IntRange(from=0) int);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecRowNum(@IntRange(from=0) int);
+ method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecType(int);
+ }
+
public class Isdbs3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
method public int getCodeRateCapability();
method public int getModulationCapability();
@@ -9630,6 +9718,7 @@
method public boolean tearDownInterfaces();
method public boolean tearDownSoftApInterface(@NonNull String);
method public void unregisterCountryCodeChangedListener(@NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangedListener);
+ field public static final String EXTRA_SCANNING_PARAM_VENDOR_IES = "android.net.wifi.nl80211.extra.SCANNING_PARAM_VENDOR_IES";
field public static final String SCANNING_PARAM_ENABLE_6GHZ_RNR = "android.net.wifi.nl80211.SCANNING_PARAM_ENABLE_6GHZ_RNR";
field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
@@ -10415,6 +10504,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public long[] getSerialNumbersOfUsers(boolean);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public android.content.pm.UserProperties getUserProperties(@NonNull android.os.UserHandle);
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int getUserSwitchability();
@@ -10423,11 +10513,11 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
method public boolean isCloneProfile();
- method public boolean isCredentialSharableWithParent();
+ method @Deprecated public boolean isCredentialSharableWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isMainUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
- method public boolean isMediaSharedWithParent();
+ method @Deprecated public boolean isMediaSharedWithParent();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
method public static boolean isRemoveResultSuccessful(int);
method public boolean isRestrictedProfile();
@@ -16566,6 +16656,7 @@
public interface WindowManager extends android.view.ViewManager {
method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
+ method @NonNull public default java.util.List<android.content.ComponentName> notifyScreenshotListeners(int);
method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback);
method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
}
@@ -16595,6 +16686,7 @@
method public void interrupt();
method public void onAccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent);
method public void onProxyConnected();
+ method public void setAccessibilityFocusAppearance(int, @ColorInt int);
method public void setInstalledAndEnabledServices(@NonNull java.util.List<android.accessibilityservice.AccessibilityServiceInfo>);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 3a6173c..b6232cd 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -16,6 +16,7 @@
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
field public static final String CONTROL_DEVICE_STATE = "android.permission.CONTROL_DEVICE_STATE";
+ field public static final String DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA = "android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA";
field public static final String FORCE_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
@@ -759,6 +760,7 @@
method public int getUserId();
method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
+ method public void updateDeviceId(int);
field public static final String ATTENTION_SERVICE = "attention";
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
@@ -945,6 +947,13 @@
field public String userType;
}
+ public final class UserProperties implements android.os.Parcelable {
+ method public int getShowInLauncher();
+ field public static final int SHOW_IN_LAUNCHER_NO = 2; // 0x2
+ field public static final int SHOW_IN_LAUNCHER_SEPARATE = 1; // 0x1
+ field public static final int SHOW_IN_LAUNCHER_WITH_PARENT = 0; // 0x0
+ }
+
}
package android.content.res {
@@ -974,6 +983,59 @@
}
+package android.credentials {
+
+ public final class CredentialDescription implements android.os.Parcelable {
+ ctor public CredentialDescription(@NonNull String, @NonNull String, @NonNull java.util.List<android.service.credentials.CredentialEntry>);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.service.credentials.CredentialEntry> getCredentialEntries();
+ method @NonNull public String getFlattenedRequestString();
+ method @NonNull public String getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CredentialDescription> CREATOR;
+ }
+
+ public final class CredentialManager {
+ method public void registerCredentialDescription(@NonNull android.credentials.RegisterCredentialDescriptionRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.RegisterCredentialDescriptionException>);
+ method public void unRegisterCredentialDescription(@NonNull android.credentials.UnregisterCredentialDescriptionRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.UnregisterCredentialDescriptionException>);
+ }
+
+ public class RegisterCredentialDescriptionException extends java.lang.Exception {
+ ctor public RegisterCredentialDescriptionException(@NonNull String, @Nullable String);
+ ctor public RegisterCredentialDescriptionException(@NonNull String, @Nullable String, @Nullable Throwable);
+ ctor public RegisterCredentialDescriptionException(@NonNull String, @Nullable Throwable);
+ ctor public RegisterCredentialDescriptionException(@NonNull String);
+ field @NonNull public final String errorType;
+ }
+
+ public final class RegisterCredentialDescriptionRequest implements android.os.Parcelable {
+ ctor public RegisterCredentialDescriptionRequest(@NonNull android.credentials.CredentialDescription);
+ ctor public RegisterCredentialDescriptionRequest(@NonNull java.util.List<android.credentials.CredentialDescription>);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.credentials.CredentialDescription> getCredentialDescriptions();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.RegisterCredentialDescriptionRequest> CREATOR;
+ field public static final String FLATTENED_REQUEST_STRING_KEY = "flattened_request_string";
+ }
+
+ public class UnregisterCredentialDescriptionException extends java.lang.Exception {
+ ctor public UnregisterCredentialDescriptionException(@NonNull String, @Nullable String);
+ ctor public UnregisterCredentialDescriptionException(@NonNull String, @Nullable String, @Nullable Throwable);
+ ctor public UnregisterCredentialDescriptionException(@NonNull String, @Nullable Throwable);
+ ctor public UnregisterCredentialDescriptionException(@NonNull String);
+ field @NonNull public final String errorType;
+ }
+
+ public final class UnregisterCredentialDescriptionRequest implements android.os.Parcelable {
+ ctor public UnregisterCredentialDescriptionRequest(@NonNull android.credentials.CredentialDescription);
+ method public int describeContents();
+ method @NonNull public android.credentials.CredentialDescription getCredentialDescription();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.UnregisterCredentialDescriptionRequest> CREATOR;
+ }
+
+}
+
package android.credentials.ui {
public final class CreateCredentialProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
@@ -1644,7 +1706,7 @@
method @NonNull public java.util.Map<java.lang.Integer,java.lang.Boolean> getSurroundFormats();
method public boolean hasRegisteredDynamicPolicy();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public boolean isCsdEnabled();
- method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE, android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public boolean isFullVolumeDevice();
method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable();
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int requestAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public void setCsd(float);
@@ -3367,6 +3429,7 @@
}
public final class InputMethodInfo implements android.os.Parcelable {
+ ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, boolean, @NonNull String);
ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c0239e8..3c17a33 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -26,6 +27,7 @@
import static java.lang.Character.MIN_VALUE;
import android.annotation.CallSuper;
+import android.annotation.CallbackExecutor;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
@@ -1016,6 +1018,7 @@
private ComponentCallbacksController mCallbacksController;
@Nullable private IVoiceInteractionManagerService mVoiceInteractionManagerService;
+ private ScreenCaptureCallbackHandler mScreenCaptureCallbackHandler;
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
@@ -9222,4 +9225,43 @@
}
return mWindow.getOnBackInvokedDispatcher();
}
+
+ /**
+ * Interface for observing screen captures of an {@link Activity}.
+ */
+ public interface ScreenCaptureCallback {
+ /**
+ * Called when one of the monitored activities is captured.
+ * This is not invoked if the activity window
+ * has {@link WindowManager.LayoutParams#FLAG_SECURE} set.
+ */
+ void onScreenCaptured();
+ }
+
+ /**
+ * Registers a screen capture callback for this activity.
+ * The callback will be triggered when a screen capture of this activity is attempted.
+ * This callback will be executed on the thread of the passed {@code executor}.
+ * For details, see {@link ScreenCaptureCallback#onScreenCaptured}.
+ */
+ @RequiresPermission(DETECT_SCREEN_CAPTURE)
+ public void registerScreenCaptureCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ScreenCaptureCallback callback) {
+ if (mScreenCaptureCallbackHandler == null) {
+ mScreenCaptureCallbackHandler = new ScreenCaptureCallbackHandler(mToken);
+ }
+ mScreenCaptureCallbackHandler.registerScreenCaptureCallback(executor, callback);
+ }
+
+
+ /**
+ * Unregisters a screen capture callback for this surface.
+ */
+ @RequiresPermission(DETECT_SCREEN_CAPTURE)
+ public void unregisterScreenCaptureCallback(@NonNull ScreenCaptureCallback callback) {
+ if (mScreenCaptureCallbackHandler != null) {
+ mScreenCaptureCallbackHandler.unregisterScreenCaptureCallback(callback);
+ }
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 89740af..12899f2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3062,7 +3062,14 @@
@Override
public boolean isDeviceContext() {
- return mIsExplicitDeviceId || isAssociatedWithDisplay();
+ if (mIsExplicitDeviceId) {
+ if (mDeviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT) {
+ return true;
+ }
+ VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
+ return vdm.isValidVirtualDeviceId(mDeviceId);
+ }
+ return isAssociatedWithDisplay();
}
@Override
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 461aa3c..e97e711 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -28,6 +28,7 @@
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
+import android.app.IScreenCaptureObserver;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
import android.app.ITaskStackListener;
@@ -354,4 +355,23 @@
*/
android.window.BackNavigationInfo startBackNavigation(
in IWindowFocusObserver focusObserver, in BackAnimationAdapter adaptor);
+
+ /**
+ * registers a callback to be invoked when the screen is captured.
+ *
+ * @param observer callback to be registered.
+ * @param activityToken The token for the activity to set the callback to.
+ * @hide
+ */
+ void registerScreenCaptureObserver(IBinder activityToken, IScreenCaptureObserver observer);
+
+ /**
+ * unregisters the screen capture callback which was registered with
+ * {@link #registerScreenCaptureObserver(ScreenCaptureObserver)}.
+ *
+ * @param observer callback to be unregistered.
+ * @param activityToken The token for the activity to unset the callback from.
+ * @hide
+ */
+ void unregisterScreenCaptureObserver(IBinder activityToken, IScreenCaptureObserver observer);
}
diff --git a/core/java/android/app/IScreenCaptureObserver.aidl b/core/java/android/app/IScreenCaptureObserver.aidl
new file mode 100644
index 0000000..1668e5d10
--- /dev/null
+++ b/core/java/android/app/IScreenCaptureObserver.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.app;
+
+/** {@hide} */
+interface IScreenCaptureObserver {
+ oneway void onScreenCaptured();
+}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 20869e0..6206f31 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -88,6 +88,7 @@
per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS
per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS
per-file ConfigurationController.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *ScreenCapture* = file:/services/core/java/com/android/server/wm/OWNERS
# TODO(b/174932174): determine the ownership of KeyguardManager.java
diff --git a/core/java/android/app/ScreenCaptureCallbackHandler.java b/core/java/android/app/ScreenCaptureCallbackHandler.java
new file mode 100644
index 0000000..997cf51
--- /dev/null
+++ b/core/java/android/app/ScreenCaptureCallbackHandler.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+
+import java.util.concurrent.Executor;
+
+/** Handles screen capture callbacks.
+ * @hide
+ **/
+public class ScreenCaptureCallbackHandler {
+
+ private final IBinder mActivityToken;
+ private final ScreenCaptureObserver mObserver;
+ private final ArrayMap<Activity.ScreenCaptureCallback, ScreenCaptureRegistration>
+ mScreenCaptureRegistrations = new ArrayMap<>();
+
+ public ScreenCaptureCallbackHandler(@NonNull IBinder activityToken) {
+ mActivityToken = activityToken;
+ mObserver = new ScreenCaptureObserver(mScreenCaptureRegistrations);
+ }
+
+ private static class ScreenCaptureRegistration {
+ Executor mExecutor;
+ Activity.ScreenCaptureCallback mCallback;
+
+ ScreenCaptureRegistration(Executor executor, Activity.ScreenCaptureCallback callback) {
+ this.mExecutor = executor;
+ this.mCallback = callback;
+ }
+ }
+
+ private static class ScreenCaptureObserver extends IScreenCaptureObserver.Stub {
+ ArrayMap<Activity.ScreenCaptureCallback, ScreenCaptureRegistration> mRegistrations;
+
+ ScreenCaptureObserver(
+ ArrayMap<Activity.ScreenCaptureCallback, ScreenCaptureRegistration>
+ registrations) {
+ this.mRegistrations = registrations;
+ }
+
+ @Override
+ public void onScreenCaptured() {
+ for (ScreenCaptureRegistration registration : mRegistrations.values()) {
+ registration.mExecutor.execute(
+ () -> {
+ registration.mCallback.onScreenCaptured();
+ });
+ }
+ }
+ }
+
+ /**
+ * Start monitoring for screen captures of the activity, the callback will be triggered whenever
+ * a screen capture is attempted. This callback will be executed on the thread of the passed
+ * {@code executor}. If the window is FLAG_SECURE, the callback will not be triggered.
+ */
+ public void registerScreenCaptureCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Activity.ScreenCaptureCallback callback) {
+ ScreenCaptureRegistration registration =
+ new ScreenCaptureRegistration(executor, callback);
+ synchronized (mScreenCaptureRegistrations) {
+ if (mScreenCaptureRegistrations.containsKey(callback)) {
+ throw new IllegalStateException(
+ "Capture observer already registered with the activity");
+ }
+ mScreenCaptureRegistrations.put(callback, registration);
+ // register with system server only once.
+ if (mScreenCaptureRegistrations.size() == 1) {
+ try {
+ ActivityTaskManager.getService()
+ .registerScreenCaptureObserver(mActivityToken, mObserver);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+ /** Stop monitoring for screen captures of the activity */
+ public void unregisterScreenCaptureCallback(@NonNull Activity.ScreenCaptureCallback callback) {
+ synchronized (mScreenCaptureRegistrations) {
+ if (!mScreenCaptureRegistrations.containsKey(callback)) {
+ throw new IllegalStateException(
+ "Capture observer not registered with the activity");
+ }
+ mScreenCaptureRegistrations.remove(callback);
+ // unregister only if no more registrations are left
+ if (mScreenCaptureRegistrations.size() == 0) {
+ try {
+ ActivityTaskManager.getService().unregisterScreenCaptureObserver(mActivityToken,
+ mObserver);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e5523a..239111e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10042,6 +10042,58 @@
}
/**
+ * Called by a device owner or profile owner of a managed profile to set the credential manager
+ * policy.
+ *
+ * <p>Affects APIs exposed by {@link android.credentials.CredentialManager}.
+ *
+ * <p>A {@link PackagePolicy#PACKAGE_POLICY_ALLOWLIST} policy type will limit the credential
+ * providers that the user can use to the list of packages in the policy.
+ *
+ * <p>A {@link PackagePolicy#PACKAGE_POLICY_ALLOWLIST_AND_SYSTEM} policy type
+ * allows access from the OEM default credential providers and the allowlist of credential
+ * providers.
+ *
+ * <p>A {@link PackagePolicy#PACKAGE_POLICY_BLOCKLIST} policy type will block the credential
+ * providers listed in the policy from being used by the user.
+ *
+ * @param policy the policy to set, setting this value to {@code null} will allow all packages
+ * @throws SecurityException if caller is not a device owner or profile owner of a
+ * managed profile
+ */
+ public void setCredentialManagerPolicy(@Nullable PackagePolicy policy) {
+ throwIfParentInstance("setCredentialManagerPolicy");
+ if (mService != null) {
+ try {
+ mService.setCredentialManagerPolicy(policy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Called by a device owner or profile owner of a managed profile to retrieve the credential
+ * manager policy.
+ *
+ * @throws SecurityException if caller is not a device owner or profile owner of a
+ * managed profile.
+ * @return the current credential manager policy if null then this policy has not been
+ * configured.
+ */
+ public @Nullable PackagePolicy getCredentialManagerPolicy() {
+ throwIfParentInstance("getCredentialManagerPolicy");
+ if (mService != null) {
+ try {
+ return mService.getCredentialManagerPolicy();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Called by a profile owner of a managed profile to set the packages that are allowed to
* lookup contacts in the managed profile based on caller id information.
* <p>
@@ -11049,6 +11101,7 @@
* @throws SecurityException if the caller is not a profile owner on an organization-owned
* managed profile.
* @throws IllegalStateException if called after the device setup has been completed.
+ * @throws UnsupportedOperationException if the api is not enabled.
* @see ManagedSubscriptionsPolicy
*/
public void setManagedSubscriptionsPolicy(@Nullable ManagedSubscriptionsPolicy policy) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index aebeaf0..70b63e4 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -336,6 +336,9 @@
PackagePolicy getManagedProfileCallerIdAccessPolicy();
boolean hasManagedProfileCallerIdAccess(int userId, String packageName);
+ void setCredentialManagerPolicy(in PackagePolicy policy);
+ PackagePolicy getCredentialManagerPolicy();
+
void setManagedProfileContactsAccessPolicy(in PackagePolicy policy);
PackagePolicy getManagedProfileContactsAccessPolicy();
boolean hasManagedProfileContactsAccess(int userId, String packageName);
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index a71590b..d0b4fe4 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -47,6 +47,9 @@
* Methods on this class requires the caller to hold and be granted the
* {@link Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE}.
*
+ * <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated
+ * separately. </p>
+ *
* @hide
*/
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 4d2317a..e56e53a 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -143,7 +143,7 @@
public ComponentName provider;
/**
- * The default height of the widget when added to a host, in px. The widget will get
+ * The default width of the widget when added to a host, in px. The widget will get
* at least this width, and will often be given more, depending on the host.
*
* <p>This field corresponds to the <code>android:minWidth</code> attribute in
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 1bc3091..d585e8f 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -361,8 +361,12 @@
private final Context mContext;
private final IVirtualDeviceManager mService;
private final IVirtualDevice mVirtualDevice;
+ private final Object mActivityListenersLock = new Object();
+ @GuardedBy("mActivityListenersLock")
private final ArrayMap<ActivityListener, ActivityListenerDelegate> mActivityListeners =
new ArrayMap<>();
+ private final Object mIntentInterceptorListenersLock = new Object();
+ @GuardedBy("mIntentInterceptorListenersLock")
private final ArrayMap<IntentInterceptorCallback,
VirtualIntentInterceptorDelegate> mIntentInterceptorListeners =
new ArrayMap<>();
@@ -377,9 +381,11 @@
public void onTopActivityChanged(int displayId, ComponentName topActivity) {
final long token = Binder.clearCallingIdentity();
try {
- for (int i = 0; i < mActivityListeners.size(); i++) {
- mActivityListeners.valueAt(i)
- .onTopActivityChanged(displayId, topActivity);
+ synchronized (mActivityListenersLock) {
+ for (int i = 0; i < mActivityListeners.size(); i++) {
+ mActivityListeners.valueAt(i)
+ .onTopActivityChanged(displayId, topActivity);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -390,8 +396,10 @@
public void onDisplayEmpty(int displayId) {
final long token = Binder.clearCallingIdentity();
try {
- for (int i = 0; i < mActivityListeners.size(); i++) {
- mActivityListeners.valueAt(i).onDisplayEmpty(displayId);
+ synchronized (mActivityListenersLock) {
+ for (int i = 0; i < mActivityListeners.size(); i++) {
+ mActivityListeners.valueAt(i).onDisplayEmpty(displayId);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -960,7 +968,11 @@
*/
public void addActivityListener(
@CallbackExecutor @NonNull Executor executor, @NonNull ActivityListener listener) {
- mActivityListeners.put(listener, new ActivityListenerDelegate(listener, executor));
+ final ActivityListenerDelegate delegate = new ActivityListenerDelegate(
+ Objects.requireNonNull(listener), Objects.requireNonNull(executor));
+ synchronized (mActivityListenersLock) {
+ mActivityListeners.put(listener, delegate);
+ }
}
/**
@@ -971,7 +983,9 @@
* @see #addActivityListener(Executor, ActivityListener)
*/
public void removeActivityListener(@NonNull ActivityListener listener) {
- mActivityListeners.remove(listener);
+ synchronized (mActivityListenersLock) {
+ mActivityListeners.remove(Objects.requireNonNull(listener));
+ }
}
/**
@@ -999,7 +1013,7 @@
*/
public void removeSoundEffectListener(@NonNull SoundEffectListener soundEffectListener) {
synchronized (mSoundEffectListenersLock) {
- mSoundEffectListeners.remove(soundEffectListener);
+ mSoundEffectListeners.remove(Objects.requireNonNull(soundEffectListener));
}
}
@@ -1029,7 +1043,9 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- mIntentInterceptorListeners.put(interceptorCallback, delegate);
+ synchronized (mIntentInterceptorListenersLock) {
+ mIntentInterceptorListeners.put(interceptorCallback, delegate);
+ }
}
/**
@@ -1040,14 +1056,17 @@
public void unregisterIntentInterceptor(
@NonNull IntentInterceptorCallback interceptorCallback) {
Objects.requireNonNull(interceptorCallback);
- final VirtualIntentInterceptorDelegate delegate =
- mIntentInterceptorListeners.get(interceptorCallback);
- try {
- mVirtualDevice.unregisterIntentInterceptor(delegate);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ final VirtualIntentInterceptorDelegate delegate;
+ synchronized (mIntentInterceptorListenersLock) {
+ delegate = mIntentInterceptorListeners.remove(interceptorCallback);
}
- mIntentInterceptorListeners.remove(interceptorCallback);
+ if (delegate != null) {
+ try {
+ mVirtualDevice.unregisterIntentInterceptor(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
}
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 85af877..06a3b1e 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -70,6 +70,23 @@
*/
public static final boolean DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
+ /**
+ * DeviceConfig property, within the clipboard namespace, that determines whether VirtualDevices
+ * are allowed to have siloed Clipboards for the apps running on them. If false, then clipboard
+ * access is blocked entirely for apps running on VirtualDevices.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ALLOW_VIRTUALDEVICE_SILOS =
+ "allow_virtualdevice_silos";
+
+ /**
+ * Default value for the DEVICE_CONFIG_ALLOW_VIRTUALDEVICE_SILOS property.
+ *
+ * @hide
+ */
+ public static final boolean DEVICE_CONFIG_DEFAULT_ALLOW_VIRTUALDEVICE_SILOS = false;
+
private final Context mContext;
private final Handler mHandler;
private final IClipboard mService;
@@ -133,7 +150,8 @@
clip,
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -162,6 +180,7 @@
mContext.getOpPackageName(),
mContext.getAttributionTag(),
mContext.getUserId(),
+ mContext.getDeviceId(),
sourcePackage);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -178,7 +197,8 @@
mService.clearPrimaryClip(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -197,7 +217,8 @@
return mService.getPrimaryClip(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -217,7 +238,8 @@
return mService.getPrimaryClipDescription(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -234,7 +256,8 @@
return mService.hasPrimaryClip(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -248,7 +271,8 @@
mPrimaryClipChangedServiceListener,
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -266,7 +290,8 @@
mPrimaryClipChangedServiceListener,
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -306,7 +331,8 @@
return mService.hasClipboardText(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -326,7 +352,8 @@
return mService.getPrimaryClipSource(
mContext.getOpPackageName(),
mContext.getAttributionTag(),
- mContext.getUserId());
+ mContext.getUserId(),
+ mContext.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7310138..5f1502f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7342,6 +7342,7 @@
* @see #createDeviceContext(int)
* @hide
*/
+ @TestApi
public void updateDeviceId(int deviceId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -7378,10 +7379,12 @@
/**
* Indicates whether the value of {@link Context#getDeviceId()} can be relied upon for
* this instance. It will return {@code true} for Contexts created by
- * {@link Context#createDeviceContext(int)}, as well as for UI and Display Contexts.
+ * {@link Context#createDeviceContext(int)} which reference a valid device ID, as well as for
+ * UI and Display Contexts.
* <p>
* Contexts created with {@link Context#createDeviceContext(int)} will have an explicit
- * device association, which will never change. UI Contexts and Display Contexts are
+ * device association, which will never change, even if the underlying device is closed or is
+ * removed. UI Contexts and Display Contexts are
* already associated with a display, so if the device association is not explicitly
* given, {@link Context#getDeviceId()} will return the ID of the device associated with
* the associated display. The system can assign an arbitrary device id value for Contexts not
diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl
index 46ece2b..b2216d4 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -26,22 +26,26 @@
* {@hide}
*/
interface IClipboard {
- void setPrimaryClip(in ClipData clip, String callingPackage, String attributionTag, int userId);
- void setPrimaryClipAsPackage(in ClipData clip, String callingPackage, String attributionTag, int userId,
- String sourcePackage);
- void clearPrimaryClip(String callingPackage, String attributionTag, int userId);
- ClipData getPrimaryClip(String pkg, String attributionTag, int userId);
- ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag, int userId);
- boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId);
+ void setPrimaryClip(in ClipData clip, String callingPackage, String attributionTag, int userId,
+ int deviceId);
+ void setPrimaryClipAsPackage(in ClipData clip, String callingPackage, String attributionTag,
+ int userId, int deviceId, String sourcePackage);
+ void clearPrimaryClip(String callingPackage, String attributionTag, int userId, int deviceId);
+ ClipData getPrimaryClip(String pkg, String attributionTag, int userId, int deviceId);
+ ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag,
+ int userId, int deviceId);
+ boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId, int deviceId);
void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage, String attributionTag, int userId);
+ String callingPackage, String attributionTag, int userId, int deviceId);
void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage, String attributionTag, int userId);
+ String callingPackage, String attributionTag, int userId, int deviceId);
/**
* Returns true if the clipboard contains text; false otherwise.
*/
- boolean hasClipboardText(String callingPackage, String attributionTag, int userId);
+ boolean hasClipboardText(String callingPackage, String attributionTag, int userId,
+ int deviceId);
- String getPrimaryClipSource(String callingPackage, String attributionTag, int userId);
+ String getPrimaryClipSource(String callingPackage, String attributionTag, int userId,
+ int deviceId);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a6f6b8..e8a355f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3474,6 +3474,18 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports Telephony APIs for Satellite communication.
+ *
+ * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY_MESSAGING}
+ * has been defined.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_TELEPHONY_SATELLITE = "android.hardware.telephony.satellite";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports Telephony APIs for the subscription.
*
* <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 6ca708a..a408ea6 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -388,7 +388,7 @@
*
* <ul>
* <li>
- * The type has a 1 minute timeout.
+ * The type has a 3 minute timeout.
* A foreground service of this type must be stopped within the timeout by
* {@link android.app.Service#stopSelf),
* or {@link android.content.Context#stopService).
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 51662af..824d15c 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -19,6 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;
@@ -36,7 +38,10 @@
/**
* Class holding the properties of a user that derive mostly from its user type.
+ *
+ * @hide
*/
+@SystemApi
public final class UserProperties implements Parcelable {
private static final String LOG_TAG = UserProperties.class.getSimpleName();
@@ -52,6 +57,10 @@
"crossProfileIntentFilterAccessControl";
private static final String ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY =
"crossProfileIntentResolutionStrategy";
+ private static final String ATTR_MEDIA_SHARED_WITH_PARENT =
+ "mediaSharedWithParent";
+ private static final String ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT =
+ "credentialShareableWithParent";
/** Index values of each property (to indicate whether they are present in this object). */
@IntDef(prefix = "INDEX_", value = {
@@ -62,7 +71,9 @@
INDEX_USE_PARENTS_CONTACTS,
INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA,
INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
- INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY
+ INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY,
+ INDEX_MEDIA_SHARED_WITH_PARENT,
+ INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT
})
@Retention(RetentionPolicy.SOURCE)
private @interface PropertyIndex {
@@ -75,6 +86,8 @@
private static final int INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = 5;
private static final int INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL = 6;
private static final int INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY = 7;
+ private static final int INDEX_MEDIA_SHARED_WITH_PARENT = 8;
+ private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -95,16 +108,22 @@
* Suggests that the launcher should show this user's apps in the main tab.
* That is, either this user is a full user, so its apps should be presented accordingly, or, if
* this user is a profile, then its apps should be shown alongside its parent's apps.
+ * @hide
*/
+ @TestApi
public static final int SHOW_IN_LAUNCHER_WITH_PARENT = 0;
/**
* Suggests that the launcher should show this user's apps, but separately from the apps of this
* user's parent.
+ * @hide
*/
+ @TestApi
public static final int SHOW_IN_LAUNCHER_SEPARATE = 1;
/**
* Suggests that the launcher should not show this user.
+ * @hide
*/
+ @TestApi
public static final int SHOW_IN_LAUNCHER_NO = 2;
/**
@@ -304,6 +323,8 @@
}
// Add items that have no permission requirements at all.
setShowInLauncher(orig.getShowInLauncher());
+ setMediaSharedWithParent(orig.isMediaSharedWithParent());
+ setCredentialShareableWithParent(orig.isCredentialShareableWithParent());
}
/**
@@ -337,7 +358,9 @@
* and {@link #SHOW_IN_LAUNCHER_NO}.
*
* @return whether, and how, a profile should be shown in the Launcher.
+ * @hide
*/
+ @TestApi
public @ShowInLauncher int getShowInLauncher() {
if (isPresent(INDEX_SHOW_IN_LAUNCHER)) return mShowInLauncher;
if (mDefaultProperties != null) return mDefaultProperties.mShowInLauncher;
@@ -463,13 +486,47 @@
throw new SecurityException("You don't have permission to query "
+ "updateCrossProfileIntentFiltersOnOTA");
}
-
/** @hide */
public void setUpdateCrossProfileIntentFiltersOnOTA(boolean val) {
this.mUpdateCrossProfileIntentFiltersOnOTA = val;
setPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA);
}
+ /**
+ * Returns whether a profile shares media with its parent user.
+ * This only applies for users that have parents (i.e. for profiles).
+ */
+ public boolean isMediaSharedWithParent() {
+ if (isPresent(INDEX_MEDIA_SHARED_WITH_PARENT)) return mMediaSharedWithParent;
+ if (mDefaultProperties != null) return mDefaultProperties.mMediaSharedWithParent;
+ throw new SecurityException("You don't have permission to query mediaSharedWithParent");
+ }
+ /** @hide */
+ public void setMediaSharedWithParent(boolean val) {
+ this.mMediaSharedWithParent = val;
+ setPresent(INDEX_MEDIA_SHARED_WITH_PARENT);
+ }
+ private boolean mMediaSharedWithParent;
+
+ /**
+ * Returns whether a profile can have shared lockscreen credential with its parent user.
+ * This only applies for users that have parents (i.e. for profiles).
+ */
+ public boolean isCredentialShareableWithParent() {
+ if (isPresent(INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT)) {
+ return mCredentialShareableWithParent;
+ }
+ if (mDefaultProperties != null) return mDefaultProperties.mCredentialShareableWithParent;
+ throw new SecurityException(
+ "You don't have permission to query credentialShareableWithParent");
+ }
+ /** @hide */
+ public void setCredentialShareableWithParent(boolean val) {
+ this.mCredentialShareableWithParent = val;
+ setPresent(INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT);
+ }
+ private boolean mCredentialShareableWithParent;
+
/*
Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
OTA update between user-parent
@@ -550,6 +607,8 @@
+ getCrossProfileIntentFilterAccessControl()
+ ", mCrossProfileIntentResolutionStrategy="
+ getCrossProfileIntentResolutionStrategy()
+ + ", mMediaSharedWithParent=" + isMediaSharedWithParent()
+ + ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
+ "}";
}
@@ -572,6 +631,9 @@
+ getCrossProfileIntentFilterAccessControl());
pw.println(prefix + " mCrossProfileIntentResolutionStrategy="
+ getCrossProfileIntentResolutionStrategy());
+ pw.println(prefix + " mMediaSharedWithParent=" + isMediaSharedWithParent());
+ pw.println(prefix + " mCredentialShareableWithParent="
+ + isCredentialShareableWithParent());
}
/**
@@ -629,6 +691,12 @@
case ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY:
setCrossProfileIntentResolutionStrategy(parser.getAttributeInt(i));
break;
+ case ATTR_MEDIA_SHARED_WITH_PARENT:
+ setMediaSharedWithParent(parser.getAttributeBoolean(i));
+ break;
+ case ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT:
+ setCredentialShareableWithParent(parser.getAttributeBoolean(i));
+ break;
default:
Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
}
@@ -676,6 +744,14 @@
serializer.attributeInt(null, ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY,
mCrossProfileIntentResolutionStrategy);
}
+ if (isPresent(INDEX_MEDIA_SHARED_WITH_PARENT)) {
+ serializer.attributeBoolean(null, ATTR_MEDIA_SHARED_WITH_PARENT,
+ mMediaSharedWithParent);
+ }
+ if (isPresent(INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT)) {
+ serializer.attributeBoolean(null, ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT,
+ mCredentialShareableWithParent);
+ }
}
// For use only with an object that has already had any permission-lacking fields stripped out.
@@ -690,6 +766,8 @@
dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
dest.writeInt(mCrossProfileIntentFilterAccessControl);
dest.writeInt(mCrossProfileIntentResolutionStrategy);
+ dest.writeBoolean(mMediaSharedWithParent);
+ dest.writeBoolean(mCredentialShareableWithParent);
}
/**
@@ -708,6 +786,8 @@
mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
mCrossProfileIntentFilterAccessControl = source.readInt();
mCrossProfileIntentResolutionStrategy = source.readInt();
+ mMediaSharedWithParent = source.readBoolean();
+ mCredentialShareableWithParent = source.readBoolean();
}
@Override
@@ -743,6 +823,8 @@
CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_ALL;
private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy =
CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT;
+ private boolean mMediaSharedWithParent = false;
+ private boolean mCredentialShareableWithParent = false;
public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
mShowInLauncher = showInLauncher;
@@ -794,6 +876,16 @@
return this;
}
+ public Builder setMediaSharedWithParent(boolean mediaSharedWithParent) {
+ mMediaSharedWithParent = mediaSharedWithParent;
+ return this;
+ }
+
+ public Builder setCredentialShareableWithParent(boolean credentialShareableWithParent) {
+ mCredentialShareableWithParent = credentialShareableWithParent;
+ return this;
+ }
+
/** Builds a UserProperties object with *all* values populated. */
public UserProperties build() {
return new UserProperties(
@@ -804,7 +896,9 @@
mUseParentsContacts,
mUpdateCrossProfileIntentFiltersOnOTA,
mCrossProfileIntentFilterAccessControl,
- mCrossProfileIntentResolutionStrategy);
+ mCrossProfileIntentResolutionStrategy,
+ mMediaSharedWithParent,
+ mCredentialShareableWithParent);
}
} // end Builder
@@ -816,7 +910,9 @@
@InheritDevicePolicy int inheritDevicePolicy,
boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA,
@CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
- @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy) {
+ @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy,
+ boolean mediaSharedWithParent,
+ boolean credentialShareableWithParent) {
mDefaultProperties = null;
setShowInLauncher(showInLauncher);
@@ -827,5 +923,7 @@
setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
setCrossProfileIntentFilterAccessControl(crossProfileIntentFilterAccessControl);
setCrossProfileIntentResolutionStrategy(crossProfileIntentResolutionStrategy);
+ setMediaSharedWithParent(mediaSharedWithParent);
+ setCredentialShareableWithParent(credentialShareableWithParent);
}
}
diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java
index b4310f2..ec6a396 100644
--- a/core/java/android/credentials/CredentialDescription.java
+++ b/core/java/android/credentials/CredentialDescription.java
@@ -17,6 +17,7 @@
package android.credentials;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.credentials.CredentialEntry;
@@ -32,6 +33,7 @@
* Represents the type and contained data fields of a {@link Credential}.
* @hide
*/
+@TestApi
public final class CredentialDescription implements Parcelable {
/**
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index e15cec8..232d063 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
@@ -329,6 +330,7 @@
*
* @hide
*/
+ @TestApi
public void registerCredentialDescription(
@NonNull RegisterCredentialDescriptionRequest request,
@Nullable CancellationSignal cancellationSignal,
@@ -376,6 +378,7 @@
*
* @hide
*/
+ @TestApi
public void unRegisterCredentialDescription(
@NonNull UnregisterCredentialDescriptionRequest request,
@Nullable CancellationSignal cancellationSignal,
diff --git a/core/java/android/credentials/RegisterCredentialDescriptionException.java b/core/java/android/credentials/RegisterCredentialDescriptionException.java
index 3cf5a75..d19bb8e 100644
--- a/core/java/android/credentials/RegisterCredentialDescriptionException.java
+++ b/core/java/android/credentials/RegisterCredentialDescriptionException.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.CancellationSignal;
import android.os.OutcomeReceiver;
@@ -32,6 +33,7 @@
*
* @hide
*/
+@TestApi
public class RegisterCredentialDescriptionException extends Exception {
@NonNull public final String errorType;
diff --git a/core/java/android/credentials/RegisterCredentialDescriptionRequest.java b/core/java/android/credentials/RegisterCredentialDescriptionRequest.java
index de31279..f257ac5 100644
--- a/core/java/android/credentials/RegisterCredentialDescriptionRequest.java
+++ b/core/java/android/credentials/RegisterCredentialDescriptionRequest.java
@@ -19,6 +19,7 @@
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,6 +37,7 @@
*
* @hide
*/
+@TestApi
public final class RegisterCredentialDescriptionRequest implements Parcelable {
public static final String FLATTENED_REQUEST_STRING_KEY = "flattened_request_string";
diff --git a/core/java/android/credentials/UnregisterCredentialDescriptionException.java b/core/java/android/credentials/UnregisterCredentialDescriptionException.java
index 0c786bd..a16915a 100644
--- a/core/java/android/credentials/UnregisterCredentialDescriptionException.java
+++ b/core/java/android/credentials/UnregisterCredentialDescriptionException.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.CancellationSignal;
import android.os.OutcomeReceiver;
@@ -32,6 +33,7 @@
*
* @hide
*/
+@TestApi
public class UnregisterCredentialDescriptionException extends Exception {
@NonNull public final String errorType;
diff --git a/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java b/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
index f3454c1..6cf40e7 100644
--- a/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
+++ b/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
@@ -19,6 +19,7 @@
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,7 @@
*
* @hide
*/
+@TestApi
public final class UnregisterCredentialDescriptionRequest implements Parcelable {
@NonNull
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index ff6e897..c9fc722 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -1246,7 +1246,7 @@
* between frames.</p>
*
* <p>The timestamps match the timestamps of the output surfaces with readout timestamp
- * enabled (via {@link OutputConfiguration#useReadoutTimestamp}) if:</p>
+ * enabled (via {@link OutputConfiguration#setReadoutTimestampEnabled}) if:</p>
* <ul>
* <li> Timestamp base is {@link OutputConfiguration#TIMESTAMP_BASE_DEFAULT} and the
* output
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 11b80cc..f20b25f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -4600,7 +4600,7 @@
* {@link CameraCaptureSession.CaptureCallback#onCaptureStarted }.</p>
* <p>In addition, the application can switch an output surface's timestamp from start of
* exposure to start of readout by calling
- * {@link android.hardware.camera2.params.OutputConfiguration#useReadoutTimestamp }.</p>
+ * {@link android.hardware.camera2.params.OutputConfiguration#setReadoutTimestampEnabled }.</p>
* <p>The readout timestamp is beneficial for video recording, because the encoder favors
* uniform timestamps, and the readout timestamps better reflect the cadence camera sensors
* output data.</p>
@@ -5688,4 +5688,5 @@
+
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3d83009..381c87d 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -4198,4 +4198,5 @@
+
}
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index dad7d3e..635e79c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -5699,4 +5699,5 @@
+
}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 8b7c5ec..857f62d 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -257,7 +257,7 @@
/**
* Timestamp is the start of readout in the same time domain as TIMESTAMP_BASE_SENSOR.
*
- * <p>NOTE: do not use! Use useReadoutTimestamp instead.</p>
+ * <p>NOTE: do not use! Use setReadoutTimestampEnabled instead.</p>
*
* @hide
*/
@@ -574,7 +574,7 @@
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
mMirrorMode = MIRROR_MODE_AUTO;
- mUseReadoutTimestamp = false;
+ mReadoutTimestampEnabled = false;
mIsReadoutSensorTimestampBase = false;
}
@@ -676,7 +676,7 @@
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
- mUseReadoutTimestamp = false;
+ mReadoutTimestampEnabled = false;
mIsReadoutSensorTimestampBase = false;
}
@@ -1050,7 +1050,7 @@
if (timestampBase == TIMESTAMP_BASE_READOUT_SENSOR) {
mTimestampBase = TIMESTAMP_BASE_SENSOR;
- mUseReadoutTimestamp = true;
+ mReadoutTimestampEnabled = true;
mIsReadoutSensorTimestampBase = true;
} else {
mTimestampBase = timestampBase;
@@ -1131,14 +1131,16 @@
* @param on The output image timestamp is the start of exposure time if false, and
* the start of readout time if true.
*/
- public void useReadoutTimestamp(boolean on) {
- mUseReadoutTimestamp = on;
+ public void setReadoutTimestampEnabled(boolean on) {
+ mReadoutTimestampEnabled = on;
}
/** Whether readout timestamp is used for this OutputConfiguration.
+ *
+ * @see #setReadoutTimestampEnabled
*/
- public boolean isReadoutTimestampUsed() {
- return mUseReadoutTimestamp;
+ public boolean isReadoutTimestampEnabled() {
+ return mReadoutTimestampEnabled;
}
/**
@@ -1172,7 +1174,7 @@
this.mStreamUseCase = other.mStreamUseCase;
this.mTimestampBase = other.mTimestampBase;
this.mMirrorMode = other.mMirrorMode;
- this.mUseReadoutTimestamp = other.mUseReadoutTimestamp;
+ this.mReadoutTimestampEnabled = other.mReadoutTimestampEnabled;
}
/**
@@ -1200,7 +1202,7 @@
int timestampBase = source.readInt();
int mirrorMode = source.readInt();
- boolean useReadoutTimestamp = source.readInt() == 1;
+ boolean readoutTimestampEnabled = source.readInt() == 1;
mSurfaceGroupId = surfaceSetId;
mRotation = rotation;
@@ -1229,7 +1231,7 @@
mStreamUseCase = streamUseCase;
mTimestampBase = timestampBase;
mMirrorMode = mirrorMode;
- mUseReadoutTimestamp = useReadoutTimestamp;
+ mReadoutTimestampEnabled = readoutTimestampEnabled;
}
/**
@@ -1350,7 +1352,7 @@
dest.writeLong(mStreamUseCase);
dest.writeInt(mTimestampBase);
dest.writeInt(mMirrorMode);
- dest.writeInt(mUseReadoutTimestamp ? 1 : 0);
+ dest.writeInt(mReadoutTimestampEnabled ? 1 : 0);
}
/**
@@ -1385,7 +1387,7 @@
mStreamUseCase != other.mStreamUseCase ||
mTimestampBase != other.mTimestampBase ||
mMirrorMode != other.mMirrorMode ||
- mUseReadoutTimestamp != other.mUseReadoutTimestamp)
+ mReadoutTimestampEnabled != other.mReadoutTimestampEnabled)
return false;
if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) {
return false;
@@ -1428,7 +1430,7 @@
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
mDynamicRangeProfile, mColorSpace, mStreamUseCase,
- mTimestampBase, mMirrorMode, mUseReadoutTimestamp ? 1 : 0);
+ mTimestampBase, mMirrorMode, mReadoutTimestampEnabled ? 1 : 0);
}
return HashCodeHelpers.hashCode(
@@ -1438,7 +1440,7 @@
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
mDynamicRangeProfile, mColorSpace, mStreamUseCase, mTimestampBase,
- mMirrorMode, mUseReadoutTimestamp ? 1 : 0);
+ mMirrorMode, mReadoutTimestampEnabled ? 1 : 0);
}
private static final String TAG = "OutputConfiguration";
@@ -1480,8 +1482,8 @@
private int mTimestampBase;
// Mirroring mode
private int mMirrorMode;
- // Use readout timestamp
- private boolean mUseReadoutTimestamp;
+ // readout timestamp
+ private boolean mReadoutTimestampEnabled;
// Whether the timestamp base is set to READOUT_SENSOR
private boolean mIsReadoutSensorTimestampBase;
}
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index 5bb1f03..5615418 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -15,14 +15,20 @@
*/
package android.hardware.hdmi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import androidx.annotation.IntRange;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
- * A class to encapsulate HDMI port information. Contains the capability of the ports such as
+ * Encapsulates HDMI port information. Contains the capability of the ports such as
* HDMI-CEC, MHL, ARC(Audio Return Channel), eARC and physical address assigned to each port.
*
* @hide
@@ -35,6 +41,18 @@
/** HDMI port type: Output */
public static final int PORT_OUTPUT = 1;
+ /**
+ * @hide
+ *
+ * @see HdmiPortInfo#getType()
+ */
+ @IntDef(prefix = { "PORT_" }, value = {
+ PORT_INPUT,
+ PORT_OUTPUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PortType {}
+
private final int mId;
private final int mType;
private final int mAddress;
@@ -46,43 +64,48 @@
/**
* Constructor.
*
- * @param id identifier assigned to each port. 1 for HDMI port 1
+ * @param id identifier assigned to each port. 1 for HDMI OUT port 1
* @param type HDMI port input/output type
* @param address physical address of the port
* @param cec {@code true} if HDMI-CEC is supported on the port
* @param mhl {@code true} if MHL is supported on the port
* @param arc {@code true} if audio return channel is supported on the port
- */
- public HdmiPortInfo(int id, int type, int address, boolean cec, boolean mhl, boolean arc) {
- this(id, type, address, cec, mhl, arc, false);
- }
-
- /**
- * Constructor.
*
- * @param id identifier assigned to each port. 1 for HDMI port 1
- * @param type HDMI port input/output type
- * @param address physical address of the port
- * @param cec {@code true} if HDMI-CEC is supported on the port
- * @param mhl {@code true} if MHL is supported on the port
- * @param arc {@code true} if audio return channel is supported on the port
- * @param earc {@code true} if eARC is supported on the port
+ * @deprecated use {@link Builder()} instead
*/
- public HdmiPortInfo(int id, int type, int address,
- boolean cec, boolean mhl, boolean arc, boolean earc) {
+ @Deprecated
+ public HdmiPortInfo(int id, @PortType int type,
+ @IntRange(from = 0) int address, boolean cec, boolean mhl, boolean arc) {
mId = id;
mType = type;
mAddress = address;
mCecSupported = cec;
mArcSupported = arc;
- mEarcSupported = earc;
+ mEarcSupported = false;
mMhlSupported = mhl;
}
/**
- * Returns the port id.
+ * Converts an instance to a builder
*
- * @return port id
+ * @hide
+ */
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ private HdmiPortInfo(Builder builder) {
+ this.mId = builder.mId;
+ this.mType = builder.mType;
+ this.mAddress = builder.mAddress;
+ this.mCecSupported = builder.mCecSupported;
+ this.mArcSupported = builder.mArcSupported;
+ this.mEarcSupported = builder.mEarcSupported;
+ this.mMhlSupported = builder.mMhlSupported;
+ }
+
+ /**
+ * Returns the port id.
*/
public int getId() {
return mId;
@@ -90,26 +113,22 @@
/**
* Returns the port type.
- *
- * @return port type
*/
+ @PortType
public int getType() {
return mType;
}
/**
* Returns the port address.
- *
- * @return port address
*/
+ @IntRange(from = 0)
public int getAddress() {
return mAddress;
}
/**
* Returns {@code true} if the port supports HDMI-CEC signaling.
- *
- * @return {@code true} if the port supports HDMI-CEC signaling.
*/
public boolean isCecSupported() {
return mCecSupported;
@@ -117,8 +136,6 @@
/**
* Returns {@code true} if the port supports MHL signaling.
- *
- * @return {@code true} if the port supports MHL signaling.
*/
public boolean isMhlSupported() {
return mMhlSupported;
@@ -126,8 +143,6 @@
/**
* Returns {@code true} if the port supports audio return channel.
- *
- * @return {@code true} if the port supports audio return channel
*/
public boolean isArcSupported() {
return mArcSupported;
@@ -135,8 +150,6 @@
/**
* Returns {@code true} if the port supports eARC.
- *
- * @return {@code true} if the port supports eARC.
*/
public boolean isEarcSupported() {
return mEarcSupported;
@@ -166,7 +179,12 @@
boolean arc = (source.readInt() == 1);
boolean mhl = (source.readInt() == 1);
boolean earc = (source.readInt() == 1);
- return new HdmiPortInfo(id, type, address, cec, mhl, arc, earc);
+ return new Builder(id, type, address)
+ .setCecSupported(cec)
+ .setArcSupported(arc)
+ .setEarcSupported(earc)
+ .setMhlSupported(mhl)
+ .build();
}
@Override
@@ -225,4 +243,95 @@
return java.util.Objects.hash(
mId, mType, mAddress, mCecSupported, mArcSupported, mMhlSupported, mEarcSupported);
}
+
+ /**
+ * Builder for {@link HdmiPortInfo} instances.
+ */
+ public static final class Builder {
+ // Required parameters
+ private int mId;
+ private int mType;
+ private int mAddress;
+
+ // Optional parameters that are set to false by default.
+ private boolean mCecSupported;
+ private boolean mArcSupported;
+ private boolean mEarcSupported;
+ private boolean mMhlSupported;
+
+ /**
+ * Constructor
+ *
+ * @param id identifier assigned to each port. 1 for HDMI OUT port 1
+ * @param type HDMI port input/output type
+ * @param address physical address of the port
+ * @throws IllegalArgumentException if the parameters are invalid
+ */
+ public Builder(int id, @PortType int type, @IntRange(from = 0) int address) {
+ if (type != PORT_INPUT && type != PORT_OUTPUT) {
+ throw new IllegalArgumentException(
+ "type should be " + PORT_INPUT + " or " + PORT_OUTPUT + ".");
+ }
+ if (address < 0) {
+ throw new IllegalArgumentException("address should be positive.");
+ }
+ mId = id;
+ mType = type;
+ mAddress = address;
+ }
+
+ private Builder(@NonNull HdmiPortInfo hdmiPortInfo) {
+ mId = hdmiPortInfo.mId;
+ mType = hdmiPortInfo.mType;
+ mAddress = hdmiPortInfo.mAddress;
+ mCecSupported = hdmiPortInfo.mCecSupported;
+ mArcSupported = hdmiPortInfo.mArcSupported;
+ mEarcSupported = hdmiPortInfo.mEarcSupported;
+ mMhlSupported = hdmiPortInfo.mMhlSupported;
+ }
+
+ /**
+ * Create a new {@link HdmiPortInfo} object.
+ */
+ @NonNull
+ public HdmiPortInfo build() {
+ return new HdmiPortInfo(this);
+ }
+
+ /**
+ * Sets the value for whether the port supports HDMI-CEC signaling.
+ */
+ @NonNull
+ public Builder setCecSupported(boolean supported) {
+ mCecSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the value for whether the port supports audio return channel.
+ */
+ @NonNull
+ public Builder setArcSupported(boolean supported) {
+ mArcSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the value for whether the port supports eARC.
+ */
+ @NonNull
+ public Builder setEarcSupported(boolean supported) {
+ mEarcSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the value for whether the port supports MHL signaling.
+ */
+ @NonNull
+ public Builder setMhlSupported(boolean supported) {
+ mMhlSupported = supported;
+ return this;
+ }
+ }
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index dfd9054..f27c34c 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -175,7 +175,7 @@
* The <code>android:label</code> attribute specifies a human-readable descriptive
* label to describe the keyboard layout in the user interface, such as "English (US)".
* The <code>android:keyboardLayout</code> attribute refers to a
- * <a href="http://source.android.com/tech/input/key-character-map-files.html">
+ * <a href="https://source.android.com/docs/core/interaction/input/key-character-map-files">
* key character map</a> resource that defines the keyboard layout.
* The <code>android:keyboardLocale</code> attribute specifies a comma separated list of BCP 47
* language tags depicting the locales supported by the keyboard layout. This attribute is
diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS
index e5d0370..01b2cb9 100644
--- a/core/java/android/hardware/soundtrigger/OWNERS
+++ b/core/java/android/hardware/soundtrigger/OWNERS
@@ -1,2 +1,2 @@
-ytai@google.com
+atneya@google.com
elaurent@google.com
diff --git a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
index febc643..ef2fefc 100644
--- a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
+++ b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
@@ -39,6 +39,8 @@
private final @DisplayPortAltModeStatus int mPartnerSinkStatus;
private final @DisplayPortAltModeStatus int mCableStatus;
private final int mNumLanes;
+ private final boolean mHpd;
+ private final int mLinkTrainingStatus;
/**
* Port Partners:
@@ -103,14 +105,18 @@
mPartnerSinkStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
mCableStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
mNumLanes = 0;
+ mHpd = false;
+ mLinkTrainingStatus = 0;
}
/** @hide */
public DisplayPortAltModeInfo(int partnerSinkStatus, int cableStatus,
- int numLanes) {
+ int numLanes, boolean hpd, int linkTrainingStatus) {
mPartnerSinkStatus = partnerSinkStatus;
mCableStatus = cableStatus;
mNumLanes = numLanes;
+ mHpd = hpd;
+ mLinkTrainingStatus = linkTrainingStatus;
}
/**
@@ -155,6 +161,8 @@
dest.writeInt(mPartnerSinkStatus);
dest.writeInt(mCableStatus);
dest.writeInt(mNumLanes);
+ dest.writeBoolean(mHpd);
+ dest.writeInt(mLinkTrainingStatus);
}
@NonNull
@@ -166,6 +174,10 @@
+ mCableStatus
+ " numLanes="
+ mNumLanes
+ + " hpd="
+ + mHpd
+ + " linkTrainingStatus="
+ + mLinkTrainingStatus
+ "}";
}
@@ -195,7 +207,10 @@
int partnerSinkStatus = in.readInt();
int cableStatus = in.readInt();
int numLanes = in.readInt();
- return new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes);
+ boolean hpd = in.readBoolean();
+ int linkTrainingStatus = in.readInt();
+ return new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes, hpd,
+ linkTrainingStatus);
}
@Override
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 8e6f6dc..268db1e 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -66,73 +66,74 @@
mSessionId = sessionId;
}
- /**
- * Subclass of {@link ResultReceiver} used by
- * {@link #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)} for providing
- * callback.
- */
- private static final class IntResultReceiver extends ResultReceiver {
- @NonNull
- private IntConsumer mConsumer;
- @NonNull
+ private abstract static class OnceResultReceiver<C> extends ResultReceiver {
+ @Nullable
+ private C mConsumer;
+ @Nullable
private Executor mExecutor;
- IntResultReceiver(@NonNull Executor executor, @NonNull IntConsumer consumer) {
+ protected OnceResultReceiver(@NonNull Executor executor, @NonNull C consumer) {
super(null);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(consumer);
mExecutor = executor;
mConsumer = consumer;
}
@Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (mExecutor != null && mConsumer != null) {
- mExecutor.execute(() -> mConsumer.accept(resultCode));
- // provide callback only once.
- clear();
+ protected final void onReceiveResult(int resultCode, Bundle resultData) {
+ final Executor executor;
+ final C consumer;
+ synchronized (this) {
+ executor = mExecutor;
+ consumer = mConsumer;
+ mExecutor = null;
+ mConsumer = null;
+ }
+ if (executor != null && consumer != null) {
+ dispatch(executor, consumer, resultCode, resultData);
}
}
- private void clear() {
- mExecutor = null;
- mConsumer = null;
+ protected abstract void dispatch(@NonNull Executor executor, @NonNull C consumer, int code,
+ Bundle data);
+ }
+
+ /**
+ * Subclass of {@link ResultReceiver} used by
+ * {@link #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)} for providing
+ * callback.
+ */
+ private static final class IntResultReceiver extends OnceResultReceiver<IntConsumer> {
+ IntResultReceiver(@NonNull Executor executor, @NonNull IntConsumer consumer) {
+ super(executor, consumer);
}
- };
+
+ @Override
+ protected void dispatch(@NonNull Executor executor, @NonNull IntConsumer consumer, int code,
+ Bundle data) {
+ executor.execute(() -> consumer.accept(code));
+ }
+ }
/**
* Subclass of {@link ResultReceiver} used by
* {@link #requestTextBoundsInfo(RectF, Executor, Consumer)} for providing
* callback.
*/
- private static final class TextBoundsInfoResultReceiver extends ResultReceiver {
- @Nullable
- private Consumer<TextBoundsInfoResult> mConsumer;
- @Nullable
- private Executor mExecutor;
-
+ private static final class TextBoundsInfoResultReceiver extends
+ OnceResultReceiver<Consumer<TextBoundsInfoResult>> {
TextBoundsInfoResultReceiver(@NonNull Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
- super(null);
- mExecutor = executor;
- mConsumer = consumer;
+ super(executor, consumer);
}
@Override
- protected void onReceiveResult(@TextBoundsInfoResult.ResultCode int resultCode,
- @Nullable Bundle resultData) {
- synchronized (this) {
- if (mExecutor != null && mConsumer != null) {
- final TextBoundsInfoResult textBoundsInfoResult = new TextBoundsInfoResult(
- resultCode, TextBoundsInfo.createFromBundle(resultData));
- mExecutor.execute(() -> mConsumer.accept(textBoundsInfoResult));
- // provide callback only once.
- clear();
- }
- }
- }
-
- private void clear() {
- mExecutor = null;
- mConsumer = null;
+ protected void dispatch(@NonNull Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer, int code, Bundle data) {
+ final TextBoundsInfoResult textBoundsInfoResult = new TextBoundsInfoResult(
+ code, TextBoundsInfo.createFromBundle(data));
+ executor.execute(() -> consumer.accept(textBoundsInfoResult));
}
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ada5c55..62d9c69 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1006,12 +1006,15 @@
// been replaced with an implementation that will suspendAll and
// send VM_START.
System.out.println("Waiting for debugger first packet");
+
+ mWaiting = true;
while (!isDebuggerConnected()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
+ mWaiting = false;
System.out.println("Debug.suspendAllAndSentVmStart");
VMDebug.suspendAllAndSendVmStart();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index d1d3315..797730b 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -116,8 +116,6 @@
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean someUserHasAccount(in String accountName, in String accountType);
String getProfileType(int userId);
- boolean isMediaSharedWithParent(int userId);
- boolean isCredentialSharableWithParent(int userId);
boolean isDemoUser(int userId);
boolean isPreCreated(int userId);
UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index dca722e..4ce9184 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -123,6 +123,9 @@
@TestApi
public static final int MIN_SECONDARY_USER_ID = 10;
+ /** @hide */
+ public static final int MAX_SECONDARY_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+
/**
* (Arbitrary) user handle cache size.
* {@link #CACHED_USER_HANDLES} caches user handles in the range of
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9a25c70..d63d87d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3248,7 +3248,10 @@
* @param userHandle the user handle of the user whose information is being requested.
* @return a UserProperties object for a specific user.
* @throws IllegalArgumentException if {@code userHandle} doesn't correspond to an existing user
+ *
+ * @hide
*/
+ @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.QUERY_USERS,
@@ -5165,19 +5168,25 @@
* Returns false for any other type of user.
*
* @return true if the user shares media with its parent user, false otherwise.
+ *
+ * @deprecated use {@link #getUserProperties(UserHandle)} with
+ * {@link UserProperties#isMediaSharedWithParent()} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@UserHandleAware(
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
Manifest.permission.MANAGE_USERS,
+ Manifest.permission.QUERY_USERS,
Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
public boolean isMediaSharedWithParent() {
try {
- return mService.isMediaSharedWithParent(mUserId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ return getUserProperties(UserHandle.of(mUserId)).isMediaSharedWithParent();
+ } catch (IllegalArgumentException e) {
+ // If the user doesn't exist, return false (for historical reasons)
+ return false;
}
}
@@ -5187,19 +5196,24 @@
* This API only works for {@link UserManager#isProfile() profiles}
* and will always return false for any other user type.
*
+ * @deprecated use {@link #getUserProperties(UserHandle)} with
+ * {@link UserProperties#isCredentialShareableWithParent()} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@UserHandleAware(
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
Manifest.permission.MANAGE_USERS,
+ Manifest.permission.QUERY_USERS,
Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
public boolean isCredentialSharableWithParent() {
try {
- return mService.isCredentialSharableWithParent(mUserId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ return getUserProperties(UserHandle.of(mUserId)).isCredentialShareableWithParent();
+ } catch (IllegalArgumentException e) {
+ // If the user doesn't exist, return false (for historical reasons)
+ return false;
}
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a72ccad..80dd488 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -18,17 +18,10 @@
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
-import static android.app.AppOpsManager.OP_READ_MEDIA_AUDIO;
import static android.app.AppOpsManager.OP_READ_MEDIA_IMAGES;
-import static android.app.AppOpsManager.OP_READ_MEDIA_VIDEO;
-import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
-import static android.app.AppOpsManager.OP_WRITE_MEDIA_AUDIO;
-import static android.app.AppOpsManager.OP_WRITE_MEDIA_IMAGES;
-import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.PER_USER_RANGE;
@@ -1869,51 +1862,14 @@
// handle obscure cases like when an app targets Q but was installed on
// a device that was originally running on P before being upgraded to Q.
- /** {@hide} */
- public boolean checkPermissionReadAudio(boolean enforce,
- int pid, int uid, String packageName, @Nullable String featureId) {
- if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
- READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
- return false;
- }
- return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
- OP_READ_MEDIA_AUDIO);
- }
-
- /** {@hide} */
- public boolean checkPermissionWriteAudio(boolean enforce,
- int pid, int uid, String packageName, @Nullable String featureId) {
- if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
- WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
- return false;
- }
- return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
- OP_WRITE_MEDIA_AUDIO);
- }
-
- /** {@hide} */
- public boolean checkPermissionReadVideo(boolean enforce,
- int pid, int uid, String packageName, @Nullable String featureId) {
- if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
- READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
- return false;
- }
- return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
- OP_READ_MEDIA_VIDEO);
- }
-
- /** {@hide} */
- public boolean checkPermissionWriteVideo(boolean enforce,
- int pid, int uid, String packageName, @Nullable String featureId) {
- if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
- WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
- return false;
- }
- return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
- OP_WRITE_MEDIA_VIDEO);
- }
-
- /** {@hide} */
+ /**
+ * @deprecated This method should not be used since it check slegacy permissions,
+ * no longer valid. Clients should check the appropriate permissions directly
+ * instead (e.g. READ_MEDIA_IMAGES).
+ *
+ * {@hide}
+ */
+ @Deprecated
public boolean checkPermissionReadImages(boolean enforce,
int pid, int uid, String packageName, @Nullable String featureId) {
if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
@@ -1924,17 +1880,6 @@
OP_READ_MEDIA_IMAGES);
}
- /** {@hide} */
- public boolean checkPermissionWriteImages(boolean enforce,
- int pid, int uid, String packageName, @Nullable String featureId) {
- if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
- WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
- return false;
- }
- return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
- OP_WRITE_MEDIA_IMAGES);
- }
-
private boolean checkExternalStoragePermissionAndAppOp(boolean enforce,
int pid, int uid, String packageName, @Nullable String featureId, String permission,
int op) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 363d035..bfc5afe 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -6422,7 +6422,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -6634,7 +6634,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -6842,7 +6842,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -7003,7 +7003,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -7210,7 +7210,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -7337,7 +7337,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -7433,7 +7433,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
@@ -7762,7 +7762,7 @@
* for {@link #TYPE_CUSTOM}.
*/
public static final CharSequence getTypeLabel(Resources res, int type,
- CharSequence label) {
+ @Nullable CharSequence label) {
if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
return label;
} else {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5b05f21..ff57003 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -72,6 +72,7 @@
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.IBinder;
+import android.os.IpcDataCache;
import android.os.LocaleList;
import android.os.PowerManager;
import android.os.PowerManager.AutoPowerSaveModeTriggers;
@@ -124,6 +125,9 @@
/** @hide */
public static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
+ /** @hide default value of whether IpcDataCache is enabled or not */
+ public static final boolean IPC_DATA_CACHE_ENABLED = false;
+
// Intent actions for Settings
/**
@@ -2920,8 +2924,8 @@
public static final String AUTHORITY = "settings";
- private static final String TAG = "Settings";
- private static final boolean LOCAL_LOGV = false;
+ static final String TAG = "Settings";
+ static final boolean LOCAL_LOGV = false;
// Used in system server calling uid workaround in call()
private static boolean sInSystemServer = false;
@@ -3031,10 +3035,10 @@
}
}
- private static final class ContentProviderHolder {
+ static final class ContentProviderHolder {
private final Object mLock = new Object();
- private final Uri mUri;
+ final Uri mUri;
@GuardedBy("mLock")
@UnsupportedAppUsage
private IContentProvider mContentProvider;
@@ -3061,14 +3065,14 @@
}
// Thread-safe.
- private static class NameValueCache {
+ static class NameValueCache {
private static final boolean DEBUG = false;
- private static final String[] SELECT_VALUE_PROJECTION = new String[] {
+ static final String[] SELECT_VALUE_PROJECTION = new String[] {
Settings.NameValueTable.VALUE
};
- private static final String NAME_EQ_PLACEHOLDER = "name=?";
+ static final String NAME_EQ_PLACEHOLDER = "name=?";
// Must synchronize on 'this' to access mValues and mValuesVersion.
private final ArrayMap<String, String> mValues = new ArrayMap<>();
@@ -3089,6 +3093,14 @@
private final ArraySet<String> mAllFields;
private final ArrayMap<String, Integer> mReadableFieldsWithMaxTargetSdk;
+ private final String mSettingsType;
+
+ // Caches for settings key -> value, only for the current user
+ private final IpcDataCache<SettingsIpcDataCache.GetQuery, String> mValueCache;
+ // Cache for settings namespace -> list of settings, only for the current user
+ private final IpcDataCache<SettingsIpcDataCache.ListQuery, HashMap<String, String>>
+ mNamespaceCache;
+
@GuardedBy("this")
private GenerationTracker mGenerationTracker;
@@ -3114,6 +3126,11 @@
mReadableFieldsWithMaxTargetSdk = new ArrayMap<>();
getPublicSettingsForClass(callerClass, mAllFields, mReadableFields,
mReadableFieldsWithMaxTargetSdk);
+ mSettingsType = callerClass.getSimpleName().toLowerCase();
+ mValueCache = IPC_DATA_CACHE_ENABLED ? SettingsIpcDataCache.createValueCache(
+ mProviderHolder, mCallGetCommand, mUri, mSettingsType) : null;
+ mNamespaceCache = IPC_DATA_CACHE_ENABLED ? SettingsIpcDataCache.createListCache(
+ mProviderHolder, mCallListCommand, mSettingsType) : null;
}
public boolean putStringForUser(ContentResolver cr, String name, String value,
@@ -3212,6 +3229,30 @@
}
}
+ if (IPC_DATA_CACHE_ENABLED) {
+ if (userHandle != UserHandle.myUserId()) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "get setting for user " + userHandle
+ + " by user " + UserHandle.myUserId()
+ + " so skipping cache");
+ }
+ try {
+ return SettingsIpcDataCache.getValueFromContentProviderCall(
+ mProviderHolder, mCallGetCommand, mUri, userHandle, cr, name);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ try {
+ return mValueCache.query(new SettingsIpcDataCache.GetQuery(cr, name));
+ } catch (RuntimeException e) {
+ // Failed to query the server
+ return null;
+ }
+ }
+
+ // Fall back to old cache mechanism
final boolean isSelf = (userHandle == UserHandle.myUserId());
int currentGeneration = -1;
if (isSelf) {
@@ -3408,6 +3449,38 @@
List<String> names) {
String namespace = prefix.substring(0, prefix.length() - 1);
Config.enforceReadPermission(namespace);
+
+ if (mCallListCommand == null) {
+ // No list command specified, return empty map
+ return new ArrayMap<>();
+ }
+
+ if (IPC_DATA_CACHE_ENABLED) {
+ ArrayMap<String, String> results = new ArrayMap<>();
+ HashMap<String, String> flagsToValues;
+ try {
+ flagsToValues = mNamespaceCache.query(
+ new SettingsIpcDataCache.ListQuery(cr, prefix));
+ } catch (RuntimeException e) {
+ // Failed to query the server, return an empty map
+ return results;
+ }
+
+ if (flagsToValues != null) {
+ if (!names.isEmpty()) {
+ for (Map.Entry<String, String> flag : flagsToValues.entrySet()) {
+ if (names.contains(flag.getKey())) {
+ results.put(flag.getKey(), flag.getValue());
+ }
+ }
+ } else {
+ results.putAll(flagsToValues);
+ }
+ }
+ return results;
+ }
+
+ // Fall back to old cache mechanism
ArrayMap<String, String> keyValues = new ArrayMap<>();
int currentGeneration = -1;
@@ -3447,10 +3520,7 @@
}
}
- if (mCallListCommand == null) {
- // No list command specified, return empty map
- return keyValues;
- }
+
IContentProvider cp = mProviderHolder.getProvider(cr);
try {
@@ -3556,7 +3626,13 @@
}
}
- public void clearGenerationTrackerForTest() {
+ public void clearCachesForTest() {
+ if (IPC_DATA_CACHE_ENABLED) {
+ mValueCache.clear();
+ mNamespaceCache.clear();
+ return;
+ }
+ // Fall back to old cache mechanism
synchronized (NameValueCache.this) {
if (mGenerationTracker != null) {
mGenerationTracker.destroy();
@@ -3565,6 +3641,12 @@
mGenerationTracker = null;
}
}
+
+ public void invalidateCache() {
+ if (IPC_DATA_CACHE_ENABLED) {
+ SettingsIpcDataCache.invalidateCache(mSettingsType);
+ }
+ }
}
/**
@@ -3841,7 +3923,12 @@
/** @hide */
public static void clearProviderForTest() {
sProviderHolder.clearProviderForTest();
- sNameValueCache.clearGenerationTrackerForTest();
+ sNameValueCache.clearCachesForTest();
+ }
+
+ /** @hide */
+ public static void invalidateValueCache() {
+ sNameValueCache.invalidateCache();
}
/** @hide */
@@ -6279,7 +6366,12 @@
/** @hide */
public static void clearProviderForTest() {
sProviderHolder.clearProviderForTest();
- sNameValueCache.clearGenerationTrackerForTest();
+ sNameValueCache.clearCachesForTest();
+ }
+
+ /** @hide */
+ public static void invalidateValueCache() {
+ sNameValueCache.invalidateCache();
}
/** @hide */
@@ -9738,7 +9830,7 @@
/**
* Indicates whether "seen" notifications should be suppressed from the lockscreen.
* <p>
- * Type: int (0 for false, 1 for true)
+ * Type: int (0 for unset, 1 for true, 2 for false)
*
* @hide
*/
@@ -14568,15 +14660,6 @@
"app_auto_restriction_enabled";
/**
- * Feature flag to enable or disable the Forced App Standby feature.
- * Type: int (0 for false, 1 for true)
- * Default: 1
- * @hide
- */
- @Readable
- public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
-
- /**
* Whether or not to enable Forced App Standby on small battery devices.
* Type: int (0 for false, 1 for true)
* Default: 0
@@ -16424,7 +16507,12 @@
/** @hide */
public static void clearProviderForTest() {
sProviderHolder.clearProviderForTest();
- sNameValueCache.clearGenerationTrackerForTest();
+ sNameValueCache.clearCachesForTest();
+ }
+
+ /** @hide */
+ public static void invalidateValueCache() {
+ sNameValueCache.invalidateCache();
}
/** @hide */
@@ -18640,7 +18728,17 @@
/** @hide */
public static void clearProviderForTest() {
sProviderHolder.clearProviderForTest();
- sNameValueCache.clearGenerationTrackerForTest();
+ sNameValueCache.clearCachesForTest();
+ }
+
+ /** @hide */
+ public static void invalidateValueCache() {
+ sNameValueCache.invalidateCache();
+ }
+
+ /** @hide */
+ public static void invalidateNamespaceCache() {
+ sNameValueCache.invalidateCache();
}
private static void handleMonitorCallback(
diff --git a/core/java/android/provider/SettingsIpcDataCache.java b/core/java/android/provider/SettingsIpcDataCache.java
new file mode 100644
index 0000000..3caf293
--- /dev/null
+++ b/core/java/android/provider/SettingsIpcDataCache.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import static android.provider.Settings.CALL_METHOD_USER_KEY;
+import static android.provider.Settings.ContentProviderHolder;
+import static android.provider.Settings.LOCAL_LOGV;
+import static android.provider.Settings.NameValueCache.NAME_EQ_PLACEHOLDER;
+import static android.provider.Settings.NameValueCache.SELECT_VALUE_PROJECTION;
+import static android.provider.Settings.TAG;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.IContentProvider;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IpcDataCache;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+/** @hide */
+final class SettingsIpcDataCache {
+ private static final boolean DEBUG = true;
+ private static final int NUM_MAX_ENTRIES = 2048;
+
+ static class GetQuery {
+ @NonNull final ContentResolver mContentResolver;
+ @NonNull final String mName;
+
+ GetQuery(@NonNull ContentResolver contentResolver, @NonNull String name) {
+ mContentResolver = contentResolver;
+ mName = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GetQuery)) return false;
+ GetQuery getQuery = (GetQuery) o;
+ return mContentResolver.equals(
+ getQuery.mContentResolver) && mName.equals(getQuery.mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mContentResolver, mName);
+ }
+ }
+
+ private static class GetQueryHandler extends IpcDataCache.QueryHandler<GetQuery, String> {
+ @NonNull final ContentProviderHolder mContentProviderHolder;
+ @NonNull final String mCallGetCommand;
+ @NonNull final Uri mUri;
+ final int mUserId;
+
+ private GetQueryHandler(
+ ContentProviderHolder contentProviderHolder, String callGetCommand, Uri uri) {
+ mContentProviderHolder = contentProviderHolder;
+ mCallGetCommand = callGetCommand;
+ mUri = uri;
+ mUserId = UserHandle.myUserId();
+ }
+
+ @Nullable
+ @Override
+ public String apply(GetQuery query) {
+ try {
+ return getValueFromContentProviderCall(mContentProviderHolder, mCallGetCommand,
+ mUri, mUserId, query);
+ } catch (RemoteException e) {
+ // Throw to prevent caching
+ e.rethrowAsRuntimeException();
+ }
+ return null;
+ }
+ }
+
+ @NonNull
+ static IpcDataCache<GetQuery, String> createValueCache(
+ @NonNull ContentProviderHolder contentProviderHolder,
+ @NonNull String callGetCommand, @NonNull Uri uri, @NonNull String type) {
+ if (DEBUG) {
+ Log.i(TAG, "Creating value cache for type:" + type);
+ }
+ IpcDataCache.Config config = new IpcDataCache.Config(
+ NUM_MAX_ENTRIES, IpcDataCache.MODULE_SYSTEM, type /* apiName */);
+ return new IpcDataCache<>(config.child("get"),
+ new GetQueryHandler(contentProviderHolder, callGetCommand, uri));
+ }
+
+ @Nullable
+ private static String getValueFromContentProviderCall(
+ @NonNull ContentProviderHolder providerHolder, @NonNull String callGetCommand,
+ @NonNull Uri uri, int userId, @NonNull GetQuery query)
+ throws RemoteException {
+ final ContentResolver cr = query.mContentResolver;
+ final String name = query.mName;
+ return getValueFromContentProviderCall(providerHolder, callGetCommand, uri, userId, cr,
+ name);
+ }
+
+ @Nullable
+ static String getValueFromContentProviderCall(
+ @NonNull ContentProviderHolder providerHolder, @NonNull String callGetCommand,
+ @NonNull Uri uri, int userId, ContentResolver cr, String name) throws RemoteException {
+ final IContentProvider cp = providerHolder.getProvider(cr);
+
+ // Try the fast path first, not using query(). If this
+ // fails (alternate Settings provider that doesn't support
+ // this interface?) then we fall back to the query/table
+ // interface.
+ if (callGetCommand != null) {
+ try {
+ Bundle args = new Bundle();
+ if (userId != UserHandle.myUserId()) {
+ args.putInt(CALL_METHOD_USER_KEY, userId);
+ }
+ Bundle b;
+ // If we're in system server and in a binder transaction we need to clear the
+ // calling uid. This works around code in system server that did not call
+ // clearCallingIdentity, previously this wasn't needed because reading settings
+ // did not do permission checking but that's no longer the case.
+ // Long term this should be removed and callers should properly call
+ // clearCallingIdentity or use a ContentResolver from the caller as needed.
+ if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ b = cp.call(cr.getAttributionSource(),
+ providerHolder.mUri.getAuthority(), callGetCommand, name,
+ args);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ b = cp.call(cr.getAttributionSource(),
+ providerHolder.mUri.getAuthority(), callGetCommand, name, args);
+ }
+ if (b != null) {
+ return b.getString(Settings.NameValueTable.VALUE);
+ }
+ // If the response Bundle is null, we fall through
+ // to the query interface below.
+ } catch (RemoteException e) {
+ // Not supported by the remote side? Fall through
+ // to query().
+ }
+ }
+
+ Cursor c = null;
+ try {
+ Bundle queryArgs = ContentResolver.createSqlQueryBundle(
+ NAME_EQ_PLACEHOLDER, new String[]{name}, null);
+ // Same workaround as above.
+ if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ c = cp.query(cr.getAttributionSource(), uri,
+ SELECT_VALUE_PROJECTION, queryArgs, null);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ c = cp.query(cr.getAttributionSource(), uri,
+ SELECT_VALUE_PROJECTION, queryArgs, null);
+ }
+ if (c == null) {
+ Log.w(TAG, "Can't get key " + name + " from " + uri);
+ return null;
+ }
+ String value = c.moveToNext() ? c.getString(0) : null;
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "cache miss [" + uri.getLastPathSegment() + "]: "
+ + name + " = " + (value == null ? "(null)" : value));
+ }
+ return value;
+ } finally {
+ if (c != null) c.close();
+ }
+ }
+
+ static class ListQuery {
+ @NonNull ContentResolver mContentResolver;
+ @NonNull final String mPrefix;
+ ListQuery(@NonNull ContentResolver contentResolver, String prefix) {
+ mContentResolver = contentResolver;
+ mPrefix = prefix;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ListQuery)) return false;
+ ListQuery listQuery = (ListQuery) o;
+ return mContentResolver.equals(listQuery.mContentResolver) && mPrefix.equals(
+ listQuery.mPrefix);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mContentResolver, mPrefix);
+ }
+ }
+
+ private static class ListQueryHandler extends
+ IpcDataCache.QueryHandler<ListQuery, HashMap<String, String>> {
+ @NonNull final ContentProviderHolder mContentProviderHolder;
+ @NonNull final String mCallListCommand;
+
+ ListQueryHandler(@NonNull ContentProviderHolder contentProviderHolder,
+ @NonNull String callListCommand) {
+ mContentProviderHolder = contentProviderHolder;
+ mCallListCommand = callListCommand;
+ }
+
+ @Nullable
+ @Override
+ public HashMap<String, String> apply(@NonNull ListQuery query) {
+ try {
+ return getListFromContentProviderCall(query);
+ } catch (RemoteException e) {
+ // Throw to prevent caching
+ e.rethrowAsRuntimeException();
+ }
+ return null;
+ }
+
+ @Nullable
+ private HashMap<String, String> getListFromContentProviderCall(ListQuery query)
+ throws RemoteException {
+ final ContentResolver cr = query.mContentResolver;
+ final IContentProvider cp = mContentProviderHolder.getProvider(cr);
+ final String prefix = query.mPrefix;
+ final String namespace = prefix.substring(0, prefix.length() - 1);
+ HashMap<String, String> keyValues = new HashMap<>();
+
+ Bundle args = new Bundle();
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
+
+ Bundle b;
+ // b/252663068: if we're in system server and the caller did not call
+ // clearCallingIdentity, the read would fail due to mismatched AttributionSources.
+ // TODO(b/256013480): remove this bypass after fixing the callers in system server.
+ if (namespace.equals(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER)
+ && Settings.isInSystemServer()
+ && Binder.getCallingUid() != Process.myUid()) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Fetch all flags for the namespace at once for caching purposes
+ b = cp.call(cr.getAttributionSource(),
+ mContentProviderHolder.mUri.getAuthority(), mCallListCommand, null,
+ args);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ // Fetch all flags for the namespace at once for caching purposes
+ b = cp.call(cr.getAttributionSource(),
+ mContentProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
+ }
+ if (b == null) {
+ // Invalid response, return an empty map
+ return keyValues;
+ }
+
+ // Cache all flags for the namespace
+ HashMap<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
+ java.util.HashMap.class);
+ return flagsToValues;
+ }
+ }
+
+ @NonNull
+ static IpcDataCache<ListQuery, HashMap<String, String>> createListCache(
+ @NonNull ContentProviderHolder providerHolder,
+ @NonNull String callListCommand, String type) {
+ if (DEBUG) {
+ Log.i(TAG, "Creating cache for settings type:" + type);
+ }
+ IpcDataCache.Config config = new IpcDataCache.Config(
+ NUM_MAX_ENTRIES, IpcDataCache.MODULE_SYSTEM, type /* apiName */);
+ return new IpcDataCache<>(config.child("get"),
+ new ListQueryHandler(providerHolder, callListCommand));
+ }
+
+ static void invalidateCache(String type) {
+ if (DEBUG) {
+ Log.i(TAG, "Cache invalidated for type:" + type);
+ }
+ IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, type);
+ }
+}
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index a389223..ff14404 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -70,7 +70,7 @@
@Override
public void onDestroy() {
- if (mCallback != null) {
+ if (mCallback != null && !isFinishing()) {
mCallback.onActivityDestroyed();
}
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index 8f49bcb..e7e44a5 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -61,6 +61,9 @@
* </service>}
* </pre>
*
+ * <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated
+ * separately. </p>
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 70b04a1..06fe523 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -166,6 +166,13 @@
public static final String SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS =
"settings_show_udfps_enroll_in_settings";
+ /**
+ * Flag to enable lock screen credentials transfer API in Android U.
+ * @hide
+ */
+ public static final String SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API =
+ "settings_enable_lockscreen_transfer_api";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -207,6 +214,7 @@
DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false");
DEFAULT_FLAGS.put(SETTINGS_FLASH_ALERTS, "false");
DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "false");
+ DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "false");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9fdda29..4f3c5fe 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -22,6 +22,7 @@
import com.android.internal.policy.IShortcutService;
import android.app.IAssistDataReceiver;
+import android.content.ComponentName;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -1000,4 +1001,14 @@
* Mark a SurfaceSyncGroup stored in WindowManager as ready.
*/
oneway void markSurfaceSyncGroupReady(in IBinder syncGroupToken);
+
+ /**
+ * Invoked when a screenshot is taken of the default display to notify registered listeners.
+ *
+ * Should be invoked only by SysUI.
+ *
+ * @param displayId id of the display screenshot.
+ * @return List of ComponentNames corresponding to the activities that were notified.
+ */
+ List<ComponentName> notifyScreenshotListeners(int displayId);
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index df78827..99a7fe5 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -640,6 +640,10 @@
mConstructorArgs[0] = inflaterContext;
View result = root;
+ if (root != null && root.getViewRootImpl() != null) {
+ root.getViewRootImpl().notifyRendererOfExpensiveFrame();
+ }
+
try {
advanceToRootNode(parser);
final String name = parser.getName();
@@ -662,6 +666,10 @@
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
+ if (root == null && temp != null && temp.getViewRootImpl() != null) {
+ temp.getViewRootImpl().notifyRendererOfExpensiveFrame();
+ }
+
ViewGroup.LayoutParams params = null;
if (root != null) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 164a494..9c6e823 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -594,6 +594,13 @@
}
}
+ @Override
+ public void notifyExpensiveFrame() {
+ if (isEnabled()) {
+ super.notifyExpensiveFrame();
+ }
+ }
+
/**
* Updates the light position based on the position of the window.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5dccd06..5165478 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2334,6 +2334,18 @@
}
}
+ /**
+ * Notifies the HardwareRenderer of an expensive upcoming frame, to
+ * allow better handling of power and scheduling requirements.
+ *
+ * @hide
+ */
+ void notifyRendererOfExpensiveFrame() {
+ if (mAttachInfo.mThreadedRenderer != null) {
+ mAttachInfo.mThreadedRenderer.notifyExpensiveFrame();
+ }
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void scheduleTraversals() {
if (!mTraversalScheduled) {
diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java
index 251ae9b..25f29a7 100644
--- a/core/java/android/view/WindowAnimationFrameStats.java
+++ b/core/java/android/view/WindowAnimationFrameStats.java
@@ -32,7 +32,12 @@
* #getRefreshPeriodNano()}. If the system does not render a frame every refresh
* period the user will see irregular window transitions. The time when the frame was
* actually presented on the display by calling {@link #getFramePresentedTimeNano(int)}.
+ *
+ * @deprecated Use Shared
+ * <a href="https://perfetto.dev/docs/data-sources/frametimeline">FrameTimeline</a>
+ * jank metrics instead.
*/
+@Deprecated
public final class WindowAnimationFrameStats extends FrameStats implements Parcelable {
/**
* @hide
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e437c1f..5f6f55a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -94,6 +94,7 @@
import android.app.Presentation;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -5269,4 +5270,18 @@
default Bitmap snapshotTaskForRecents(@IntRange(from = 0) int taskId) {
return null;
}
+
+ /**
+ * Invoked when a screenshot is taken of the default display to notify registered listeners.
+ *
+ * Should be invoked only by SysUI.
+ *
+ * @param displayId id of the display screenshot.
+ * @return List of ComponentNames corresponding to the activities that were notified.
+ * @hide
+ */
+ @SystemApi
+ default @NonNull List<ComponentName> notifyScreenshotListeners(int displayId) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 19d49d9..7ea8c0c 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Region;
@@ -412,4 +413,15 @@
IBinder getDefaultToken() {
return mDefaultToken;
}
+
+ @Override
+ @NonNull
+ public List<ComponentName> notifyScreenshotListeners(int displayId) {
+ try {
+ return List.copyOf(WindowManagerGlobal.getWindowManagerService()
+ .notifyScreenshotListeners(displayId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index 141849f..b74b80e 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -20,6 +20,8 @@
import android.graphics.Point;
import android.graphics.Rect;
+import java.util.function.Supplier;
+
/**
* Metrics about a Window, consisting of the bounds and {@link WindowInsets}.
* <p>
@@ -50,8 +52,9 @@
public final class WindowMetrics {
@NonNull
private final Rect mBounds;
- @NonNull
- private final WindowInsets mWindowInsets;
+
+ private WindowInsets mWindowInsets;
+ private Supplier<WindowInsets> mWindowInsetsSupplier;
/** @see android.util.DisplayMetrics#density */
private final float mDensity;
@@ -81,6 +84,21 @@
}
/**
+ * Similar to {@link #WindowMetrics(Rect, WindowInsets, float)} but the window insets are
+ * computed when {@link #getWindowInsets()} is first time called. This reduces unnecessary
+ * calculation and the overhead of obtaining insets state from server side because most
+ * callers are usually only interested in {@link #getBounds()}.
+ *
+ * @hide
+ */
+ public WindowMetrics(@NonNull Rect bounds, @NonNull Supplier<WindowInsets> windowInsetsSupplier,
+ float density) {
+ mBounds = bounds;
+ mWindowInsetsSupplier = windowInsetsSupplier;
+ mDensity = density;
+ }
+
+ /**
* Returns the bounds of the area associated with this window or
* {@link android.annotation.UiContext}.
* <p>
@@ -121,7 +139,10 @@
*/
@NonNull
public WindowInsets getWindowInsets() {
- return mWindowInsets;
+ if (mWindowInsets != null) {
+ return mWindowInsets;
+ }
+ return mWindowInsets = mWindowInsetsSupplier.get();
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
index dd320e1..12e0814 100644
--- a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
+++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
@@ -22,6 +22,7 @@
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.MagnificationConfig;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -240,6 +241,27 @@
}
/**
+ * Sets the strokeWidth and color of the accessibility focus rectangle.
+ *
+ * @param strokeWidth The stroke width of the rectangle in pixels.
+ * Setting this value to zero results in no focus rectangle being drawn.
+ * @param color The color of the rectangle.
+ */
+ public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) {
+ IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setFocusAppearance(strokeWidth, color);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the "
+ + "accessibility focus rectangle", re);
+ re.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* An IAccessibilityServiceClient that handles interrupts, accessibility events, and system
* connection.
*/
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 8e335e8..3ce419e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -230,6 +230,17 @@
*/
public static final int FLAG_CONTENT_CONTROLS = 4;
+
+ /**
+ * {@link ComponentName} for the Accessibility Menu {@link AccessibilityService} as provided
+ * inside the system build, used for automatic migration to this version of the service.
+ * @hide
+ */
+ public static final ComponentName ACCESSIBILITY_MENU_IN_SYSTEM =
+ new ComponentName("com.android.systemui.accessibility.accessibilitymenu",
+ "com.android.systemui.accessibility.accessibilitymenu"
+ + ".AccessibilityMenuService");
+
@UnsupportedAppUsage
static final Object sInstanceSync = new Object();
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 229cc02..ec1badb 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -22,6 +22,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -38,6 +39,7 @@
import android.inputmethodservice.InputMethodService;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Printer;
import android.util.Slog;
@@ -71,6 +73,16 @@
* @attr ref android.R.styleable#InputMethod_configChanges
*/
public final class InputMethodInfo implements Parcelable {
+
+ /**
+ * {@link Intent#getAction() Intent action} for IME that
+ * {@link #supportsStylusHandwriting() supports stylus handwriting}.
+ *
+ * @see #createStylusHandwritingSettingsActivityIntent().
+ */
+ public static final String ACTION_STYLUS_HANDWRITING_SETTINGS =
+ "android.view.inputmethod.action.STYLUS_HANDWRITING_SETTINGS";
+
static final String TAG = "InputMethodInfo";
/**
@@ -152,6 +164,11 @@
*/
private final boolean mSupportsStylusHandwriting;
+ /**
+ * The stylus handwriting setting activity's name, used by the system settings to
+ * launch the stylus handwriting specific setting activity of this input method.
+ */
+ private final String mStylusHandwritingSettingsActivityAttr;
/**
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
@@ -203,6 +220,7 @@
PackageManager pm = context.getPackageManager();
String settingsActivityComponent = null;
+ String stylusHandwritingSettingsActivity = null;
boolean isVrOnly;
int isDefaultResId = 0;
@@ -253,6 +271,8 @@
com.android.internal.R.styleable.InputMethod_configChanges, 0);
mSupportsStylusHandwriting = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsStylusHandwriting, false);
+ stylusHandwritingSettingsActivity = sa.getString(
+ com.android.internal.R.styleable.InputMethod_stylusHandwritingSettingsActivity);
sa.recycle();
final int depth = parser.getDepth();
@@ -328,6 +348,7 @@
}
mSubtypes = new InputMethodSubtypeArray(subtypes);
mSettingsActivityName = settingsActivityComponent;
+ mStylusHandwritingSettingsActivityAttr = stylusHandwritingSettingsActivity;
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
@@ -359,6 +380,7 @@
mHandledConfigChanges = source.mHandledConfigChanges;
mSupportsStylusHandwriting = source.mSupportsStylusHandwriting;
mForceDefault = source.mForceDefault;
+ mStylusHandwritingSettingsActivityAttr = source.mStylusHandwritingSettingsActivityAttr;
}
InputMethodInfo(Parcel source) {
@@ -376,6 +398,7 @@
mSubtypes = new InputMethodSubtypeArray(source);
mHandledConfigChanges = source.readInt();
mSupportsStylusHandwriting = source.readBoolean();
+ mStylusHandwritingSettingsActivityAttr = source.readString8();
mForceDefault = false;
}
@@ -389,10 +412,28 @@
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
0 /* handledConfigChanges */, false /* supportsStylusHandwriting */,
+ null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
/**
+ * Test API for creating a built-in input method to verify stylus handwriting.
+ * @hide
+ */
+ @TestApi
+ public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+ @NonNull CharSequence label, @NonNull String settingsActivity,
+ boolean supportStylusHandwriting,
+ @NonNull String stylusHandwritingSettingsActivityAttr) {
+ this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+ settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
+ false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+ 0 /* handledConfigChanges */, supportStylusHandwriting,
+ stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
+ }
+
+ /**
* Temporary API for creating a built-in input method for test.
* @hide
*/
@@ -405,6 +446,7 @@
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges,
false /* supportsStylusHandwriting */,
+ null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -419,6 +461,7 @@
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
false /* isVrOnly */, 0 /* handledconfigChanges */,
false /* supportsStylusHandwriting */,
+ null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -432,6 +475,7 @@
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
0 /* handledConfigChanges */, false /* supportsStylusHandwriting */,
+ null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -443,6 +487,7 @@
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
boolean isVrOnly, int handledConfigChanges, boolean supportsStylusHandwriting,
+ String stylusHandwritingSettingsActivityAttr,
boolean supportsInlineSuggestionsWithTouchExploration) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
@@ -461,6 +506,7 @@
mIsVrOnly = isVrOnly;
mHandledConfigChanges = handledConfigChanges;
mSupportsStylusHandwriting = supportsStylusHandwriting;
+ mStylusHandwritingSettingsActivityAttr = stylusHandwritingSettingsActivityAttr;
}
private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -550,6 +596,7 @@
*
* <p>A null will be returned if there is no settings activity associated
* with the input method.</p>
+ * @see #createStylusHandwritingSettingsActivityIntent()
*/
public String getSettingsActivity() {
return mSettingsActivityName;
@@ -622,11 +669,41 @@
/**
* Returns if IME supports handwriting using stylus input.
* @attr ref android.R.styleable#InputMethod_supportsStylusHandwriting
+ * @see #createStylusHandwritingSettingsActivityIntent()
*/
public boolean supportsStylusHandwriting() {
return mSupportsStylusHandwriting;
}
+ /**
+ * Returns {@link Intent} for stylus handwriting settings activity with
+ * {@link Intent#getAction() Intent action} {@link #ACTION_STYLUS_HANDWRITING_SETTINGS}
+ * if IME {@link #supportsStylusHandwriting() supports stylus handwriting}, else
+ * <code>null</code> if there are no associated settings for stylus handwriting / handwriting
+ * is not supported or if
+ * {@link android.R.styleable#InputMethod_stylusHandwritingSettingsActivity} is not defined.
+ *
+ * <p>To launch stylus settings, use this method to get the {@link android.content.Intent} to
+ * launch the stylus handwriting settings activity.</p>
+ * <p>e.g.<pre><code>startActivity(createStylusHandwritingSettingsActivityIntent());</code>
+ * </pre></p>
+ *
+ * @attr ref R.styleable#InputMethod_stylusHandwritingSettingsActivity
+ * @see #getSettingsActivity()
+ * @see #supportsStylusHandwriting()
+ */
+ @Nullable
+ public Intent createStylusHandwritingSettingsActivityIntent() {
+ if (TextUtils.isEmpty(mStylusHandwritingSettingsActivityAttr)
+ || !mSupportsStylusHandwriting) {
+ return null;
+ }
+ // TODO(b/210039666): consider returning null if component is not enabled.
+ return new Intent(ACTION_STYLUS_HANDWRITING_SETTINGS).setComponent(
+ new ComponentName(getServiceInfo().packageName,
+ mStylusHandwritingSettingsActivityAttr));
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
@@ -637,7 +714,9 @@
+ mSupportsInlineSuggestionsWithTouchExploration
+ " mSuppressesSpellChecker=" + mSuppressesSpellChecker
+ " mShowInInputMethodPicker=" + mShowInInputMethodPicker
- + " mSupportsStylusHandwriting=" + mSupportsStylusHandwriting);
+ + " mSupportsStylusHandwriting=" + mSupportsStylusHandwriting
+ + " mStylusHandwritingSettingsActivityAttr="
+ + mStylusHandwritingSettingsActivityAttr);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
pw.println(prefix + "Service:");
@@ -752,6 +831,7 @@
mSubtypes.writeToParcel(dest);
dest.writeInt(mHandledConfigChanges);
dest.writeBoolean(mSupportsStylusHandwriting);
+ dest.writeString8(mStylusHandwritingSettingsActivityAttr);
}
/**
diff --git a/core/java/android/window/WindowMetricsController.java b/core/java/android/window/WindowMetricsController.java
index 06449d5..11bd47d 100644
--- a/core/java/android/window/WindowMetricsController.java
+++ b/core/java/android/window/WindowMetricsController.java
@@ -41,6 +41,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
/**
* A controller to handle {@link android.view.WindowMetrics} related APIs, which are
@@ -53,6 +54,9 @@
* @hide
*/
public final class WindowMetricsController {
+ // TODO(b/151908239): Remove and always enable this if it is stable.
+ private static final boolean LAZY_WINDOW_INSETS = android.os.SystemProperties.getBoolean(
+ "persist.wm.debug.win_metrics_lazy_insets", false);
private final Context mContext;
public WindowMetricsController(@NonNull Context context) {
@@ -92,16 +96,11 @@
windowingMode = winConfig.getWindowingMode();
}
final IBinder token = Context.getToken(mContext);
- final WindowInsets windowInsets = getWindowInsetsFromServerForCurrentDisplay(token,
- bounds, isScreenRound, windowingMode);
- return new WindowMetrics(bounds, windowInsets, density);
- }
-
- private WindowInsets getWindowInsetsFromServerForCurrentDisplay(
- IBinder token, Rect bounds, boolean isScreenRound,
- @WindowConfiguration.WindowingMode int windowingMode) {
- return getWindowInsetsFromServerForDisplay(mContext.getDisplayId(), token, bounds,
- isScreenRound, windowingMode);
+ final Supplier<WindowInsets> insetsSupplier = () -> getWindowInsetsFromServerForDisplay(
+ mContext.getDisplayId(), token, bounds, isScreenRound, windowingMode);
+ return LAZY_WINDOW_INSETS
+ ? new WindowMetrics(new Rect(bounds), insetsSupplier, density)
+ : new WindowMetrics(new Rect(bounds), insetsSupplier.get(), density);
}
/**
diff --git a/core/java/com/android/internal/expresslog/Counter.java b/core/java/com/android/internal/expresslog/Counter.java
index 7571073..cc37c69 100644
--- a/core/java/com/android/internal/expresslog/Counter.java
+++ b/core/java/com/android/internal/expresslog/Counter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,9 +39,7 @@
* @hide
*/
public static void logIncrement(@NonNull String metricId, long amount) {
- final long metricIdHash = hashString(metricId);
+ final long metricIdHash = Utils.hashString(metricId);
FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_EVENT_REPORTED, metricIdHash, amount);
}
-
- private static native long hashString(String stringToHash);
}
diff --git a/core/java/com/android/internal/expresslog/Utils.java b/core/java/com/android/internal/expresslog/Utils.java
new file mode 100644
index 0000000..d82192f
--- /dev/null
+++ b/core/java/com/android/internal/expresslog/Utils.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.expresslog;
+
+final class Utils {
+ static native long hashString(String stringToHash);
+}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index deafd19..d9cb72a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1328,6 +1328,15 @@
level = MEMORY_TAG_LEVEL_NONE;
}
+ // If we requested "sync" mode for the whole platform, upgrade mode for apps that enable
+ // MTE.
+ // This makes debugging a lot easier.
+ if (level == MEMORY_TAG_LEVEL_ASYNC
+ && (Build.IS_USERDEBUG || Build.IS_ENG)
+ && "sync".equals(SystemProperties.get("persist.arm64.memtag.default"))) {
+ level = MEMORY_TAG_LEVEL_SYNC;
+ }
+
return level;
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index a704eb3..1c85ca2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -53,7 +53,7 @@
boolean showImeSwitcher);
void setWindowState(int display, int window, int state);
- void showRecentApps(boolean triggeredFromAltTab, boolean forward);
+ void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecentApps();
void toggleSplitScreen();
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 91d2ecb..eca85ff 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -219,7 +219,7 @@
"android_security_Scrypt.cpp",
"com_android_internal_content_om_OverlayConfig.cpp",
"com_android_internal_content_om_OverlayManagerImpl.cpp",
- "com_android_internal_expresslog_Counter.cpp",
+ "com_android_internal_expresslog_Utils.cpp",
"com_android_internal_net_NetworkUtilsInternal.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 578cf24..b550f28 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -200,7 +200,7 @@
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
extern int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env);
-extern int register_com_android_internal_expresslog_Counter(JNIEnv* env);
+extern int register_com_android_internal_expresslog_Utils(JNIEnv* env);
extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
@@ -1586,7 +1586,7 @@
REG_JNI(register_android_os_incremental_IncrementalManager),
REG_JNI(register_com_android_internal_content_om_OverlayConfig),
REG_JNI(register_com_android_internal_content_om_OverlayManagerImpl),
- REG_JNI(register_com_android_internal_expresslog_Counter),
+ REG_JNI(register_com_android_internal_expresslog_Utils),
REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index 9941ca4..34ef7b3 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -60,8 +60,14 @@
if (std::find(i.pixelFormats.begin(), i.pixelFormats.end(),
static_cast<int32_t>(HAL_PIXEL_FORMAT_RGBA_FP16)) !=
i.pixelFormats.end() &&
- std::find(i.dataspaces.begin(), i.dataspaces.end(),
- static_cast<int32_t>(HAL_DATASPACE_BT2020_PQ)) != i.dataspaces.end()) {
+ std::find(i.standards.begin(), i.standards.end(),
+ static_cast<int32_t>(HAL_DATASPACE_STANDARD_BT2020)) !=
+ i.standards.end() &&
+ std::find(i.transfers.begin(), i.transfers.end(),
+ static_cast<int32_t>(HAL_DATASPACE_TRANSFER_ST2084)) !=
+ i.transfers.end() &&
+ std::find(i.ranges.begin(), i.ranges.end(),
+ static_cast<int32_t>(HAL_DATASPACE_RANGE_FULL)) != i.ranges.end()) {
return true;
}
}
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 2ef9632..d5568df 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -157,7 +157,7 @@
static jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject clazz,
jstring label) {
ScopedUtfChars keyLabel(env, label);
- return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str());
+ return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str()).value_or(AKEYCODE_UNKNOWN);
}
static jint android_view_KeyEvent_nativeNextId() {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 88444cb..49f47c5 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -515,7 +515,7 @@
static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz,
jstring label) {
ScopedUtfChars axisLabel(env, label);
- return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
+ return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()).value_or(-1));
}
// ---------------- @FastNative ----------------------------------
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 6762e45..2c81987 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "NativeLibraryHelper"
//#define LOG_NDEBUG 0
+#include <androidfw/ApkParsing.h>
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
#include <errno.h>
@@ -37,15 +38,6 @@
#include "core_jni_helpers.h"
-#define APK_LIB "lib/"
-#define APK_LIB_LEN (sizeof(APK_LIB) - 1)
-
-#define LIB_PREFIX "/lib"
-#define LIB_PREFIX_LEN (sizeof(LIB_PREFIX) - 1)
-
-#define LIB_SUFFIX ".so"
-#define LIB_SUFFIX_LEN (sizeof(LIB_SUFFIX) - 1)
-
#define RS_BITCODE_SUFFIX ".bc"
#define TMP_FILE_PATTERN "/tmp.XXXXXX"
@@ -66,39 +58,6 @@
typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
-// Equivalent to android.os.FileUtils.isFilenameSafe
-static bool
-isFilenameSafe(const char* filename)
-{
- off_t offset = 0;
- for (;;) {
- switch (*(filename + offset)) {
- case 0:
- // Null.
- // If we've reached the end, all the other characters are good.
- return true;
-
- case 'A' ... 'Z':
- case 'a' ... 'z':
- case '0' ... '9':
- case '+':
- case ',':
- case '-':
- case '.':
- case '/':
- case '=':
- case '_':
- offset++;
- break;
-
- default:
- // We found something that is not good.
- return false;
- }
- }
- // Should not reach here.
-}
-
static bool
isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime,
uint32_t zipCrc, struct stat64* st)
@@ -330,7 +289,7 @@
static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
void* cookie = nullptr;
// Do not specify a suffix to find both .so files and gdbserver.
- if (!zipFile->startIteration(&cookie, APK_LIB, nullptr /* suffix */)) {
+ if (!zipFile->startIteration(&cookie, APK_LIB.data(), nullptr /* suffix */)) {
return nullptr;
}
@@ -345,36 +304,11 @@
continue;
}
- // Make sure the filename is at least to the minimum library name size.
- const size_t fileNameLen = strlen(fileName);
- static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
- if (fileNameLen < minLength) {
- continue;
+ const char* lastSlash = util::ValidLibraryPathLastSlash(fileName, false, mDebuggable);
+ if (lastSlash) {
+ mLastSlash = lastSlash;
+ break;
}
-
- const char* lastSlash = strrchr(fileName, '/');
- ALOG_ASSERT(lastSlash != nullptr, "last slash was null somehow for %s\n", fileName);
-
- // Skip directories.
- if (*(lastSlash + 1) == 0) {
- continue;
- }
-
- // Make sure the filename is safe.
- if (!isFilenameSafe(lastSlash + 1)) {
- continue;
- }
-
- if (!mDebuggable) {
- // Make sure the filename starts with lib and ends with ".so".
- if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
- || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
- continue;
- }
- }
-
- mLastSlash = lastSlash;
- break;
}
return next;
@@ -543,7 +477,7 @@
}
const char* lastSlash = strrchr(fileName, '/');
const char* baseName = (lastSlash == nullptr) ? fileName : fileName + 1;
- if (isFilenameSafe(baseName)) {
+ if (util::isFilenameSafe(baseName)) {
zipFile->endIteration(cookie);
return BITCODE_PRESENT;
}
diff --git a/core/jni/com_android_internal_expresslog_Counter.cpp b/core/jni/com_android_internal_expresslog_Utils.cpp
similarity index 83%
rename from core/jni/com_android_internal_expresslog_Counter.cpp
rename to core/jni/com_android_internal_expresslog_Utils.cpp
index d4a8c23..d33a7bd 100644
--- a/core/jni/com_android_internal_expresslog_Counter.cpp
+++ b/core/jni/com_android_internal_expresslog_Utils.cpp
@@ -26,7 +26,7 @@
static jclass g_stringClass = nullptr;
/**
- * Class: com_android_internal_expresslog_Counter
+ * Class: com_android_internal_expresslog_Utils
* Method: hashString
* Signature: (Ljava/lang/String;)J
*/
@@ -43,15 +43,15 @@
{"hashString", "(Ljava/lang/String;)J", (void*)hashString},
};
-static const char* const kCounterPathName = "com/android/internal/expresslog/Counter";
+static const char* const kUtilsPathName = "com/android/internal/expresslog/Utils";
namespace android {
-int register_com_android_internal_expresslog_Counter(JNIEnv* env) {
+int register_com_android_internal_expresslog_Utils(JNIEnv* env) {
jclass stringClass = FindClassOrDie(env, "java/lang/String");
g_stringClass = MakeGlobalRefOrDie(env, stringClass);
- return RegisterMethodsOrDie(env, kCounterPathName, g_methods, NELEM(g_methods));
+ return RegisterMethodsOrDie(env, kUtilsPathName, g_methods, NELEM(g_methods));
}
} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bc40cef..077b0c5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7035,6 +7035,17 @@
<permission android:name="android.permission.GET_APP_METADATA"
android:protectionLevel="signature|installer" />
+ <!-- @hide @SystemApi Allows an application to stage HealthConnect's remote data so that
+ HealthConnect can later integrate it. -->
+ <permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA"
+ android:protectionLevel="signature|knownSigner"
+ android:knownCerts="@array/config_healthConnectStagingDataKnownSigners"/>
+
+ <!-- @hide @TestApi Allows an application to clear HealthConnect's staged remote data for
+ testing only. For security reasons, this is a platform-only permission. -->
+ <permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows the holder to call health connect migration APIs.
@hide -->
<permission android:name="android.permission.MIGRATE_HEALTH_CONNECT_DATA"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 8c1b6ed..2652da6 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -326,11 +326,11 @@
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"wys kennisgewings"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Venster-inhoud ophaal"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Die inhoud ondersoek van \'n venster waarmee jy interaksie het."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Verken deur raak aanskakel"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Verken-met-raak aanskakel"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Items waarop getik word, sal hardop gesê word en die skerm kan met behulp van gebare verken word."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Teks wat jy tik waarneem"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Neem teks wat jy tik waar"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Dit sluit persoonlike data soos kredietkaartnommers en wagwoorde in."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Vertoonskermvergroting beheer"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Beheer vertoonskerm-vergroting"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Die vertoonskerm se zoemvlak en posisionering beheer."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Voer gebare uit"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tik, swiep, knyp en ander gebare uitvoer."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Skakel werkprogramme aan?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Kry toegang tot jou werkprogramme en -kennisgewings"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Noodgeval"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Kry toegang tot jou werkapps en -oproepe"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 708b9fd..d47bcab 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"የሥራ መተግበሪያዎች ይብሩ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"የእርስዎን የሥራ መተግበሪያዎች እና ማሳወቂያዎች መዳረሻ ያግኙ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"አብራ"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ድንገተኛ አደጋ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"የእርስዎን የሥራ መተግበሪያዎች እና ጥሪዎች መዳረሻ ያግኙ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e524fc7..b443e45 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1947,10 +1947,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"هل تريد تفعيل تطبيقات العمل؟"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"الوصول إلى تطبيقات العمل وإشعاراتها"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"تفعيل"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"الطوارئ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"الوصول إلى المكالمات وتطبيقات العمل"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5409045..e39a783 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -822,7 +822,7 @@
<string name="policylab_expirePassword" msgid="6015404400532459169">"স্ক্ৰীন লক পাছৱৰ্ডৰ ম্যাদ ওকলাৰ দিন ছেট কৰক"</string>
<string name="policydesc_expirePassword" msgid="9136524319325960675">"স্ক্ৰীন লকৰ পাছৱৰ্ড, পিন বা আর্হি কিমান ঘনাই সলনি কৰিব লাগিব তাক সলনি কৰক।"</string>
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"ষ্ট’ৰেজৰ এনক্ৰিপশ্বন ছেট কৰক"</string>
- <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"সঞ্চয় কৰি ৰখা ডেটাক এনক্ৰিপ্ট কৰাৰ প্ৰয়োজন।"</string>
+ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"ষ্ট’ৰ কৰি ৰখা এপৰ ডেটাক এনক্ৰিপ্ট কৰাৰ প্ৰয়োজন।"</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"কেমেৰাবোৰ অক্ষম কৰক"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"আটাইবোৰ ডিভাইচৰ কেমেৰা ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"স্ক্ৰীন লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"কৰ্মস্থানৰ এপ্ অন কৰিবনে?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"আপোনাৰ কৰ্মস্থানৰ এপ্ আৰু জাননীৰ এক্সেছ পাওক"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"জৰুৰীকালীন"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"আপোনাৰ কৰ্মস্থানৰ এপ্ আৰু জাননীৰ এক্সেছ পাওক"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index efa6c67..73bf38b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"İş tətbiqləri aktiv edilsin?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"İş tətbiqlərinizə və bildirişlərinizə giriş əldə edin"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Fövqəladə hal"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"İş tətbiqlərinizə və zənglərinizə giriş əldə edin"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0677369..237aea2 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Uključujete poslovne aplikacije?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pristupajte poslovnim aplikacijama i obaveštenjima"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitan slučaj"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Pristupajte poslovnim aplikacijama i pozivima"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 07cdb89..aae5f56 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Уключыць працоўныя праграмы?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Атрымаць доступ да працоўных праграм і апавяшчэнняў"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Уключыць"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Экстранны выпадак"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Запытайце доступ да працоўных праграм і выклікаў"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4139e95..f4d6749 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -324,17 +324,17 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"достъп до сензорните данни за жизнените ви показатели"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Известия"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"показване на известията"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Извличане на съдържанието от прозореца"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Инспектиране на съдържанието на прозорец, с който взаимодействате."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Включване на изследването чрез докосване"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Извлича съдържанието от прозореца"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Инспектира съдържанието на прозорец, с който взаимодействате."</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Включи изследването чрез докосване"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Докосваните елементи ще бъдат изговаряни на глас и екранът може да бъде изследван посредством жестове."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Наблюдение на въвеждания от вас текст"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Наблюдава въвеждания от вас текст"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Включва лични данни, като например номера на кредитни карти и пароли."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Управление на увеличението на дисплея"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Управление на нивото на мащаба и позиционирането на дисплея."</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Управлява увеличението на дисплея"</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Управлява нивото на мащаба и позиционирането на дисплея."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Извършване на жестове"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Можете да докосвате, да прекарвате пръст, да събирате пръсти и да извършвате други жестове."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Жестове за отпечатък"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Улавя жестове за отпечатък"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Може да улавя жестовете, извършени върху сензора за отпечатъци на устройството."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Създаване на екранна снимка"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Може да създава екранни снимки."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Включване на служ. приложения?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Получете достъп до служебните си приложения и известия"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включване"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Спешен случай"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Получете достъп до служебните си приложения и обаждания"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 09e592c..e669b6d 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -324,13 +324,13 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"আপনার অত্যাবশ্যক লক্ষণগুলির সম্পর্কে সেন্সর ডেটা অ্যাক্সেস করে"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"বিজ্ঞপ্তি"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"বিজ্ঞপ্তি দেখুন"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"উইন্ডোর কন্টেন্ট পুনরুদ্ধার করে"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ব্যবহার করছেন এমন একটি উইন্ডোর কন্টেন্ট নিরীক্ষণ করে৷"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"উইন্ডোর কন্টেন্ট ফিরিয়ে আনুন"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ব্যবহার করছেন এমন একটি উইন্ডোর কন্টেন্ট পরীক্ষা করে৷"</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"স্পর্শের মাধ্যমে অন্বেষণ করা চালু করুন"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"যে আইটেমগুলিতে আলতো চেপেছেন সেগুলি সশব্দে বলবে এবং ইঙ্গিতগুলি ব্যবহার করে স্ক্রিন অন্বেষণ করা যাবে৷"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"যে আইটেমগুলিতে ট্যাপ করেছেন সেগুলি জোরে বলবে এবং ইঙ্গিতগুলি ব্যবহার করে স্ক্রিন অন্বেষণ করা যাবে৷"</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"আপনার লেখা পাঠ্যকে নিরীক্ষণ করে"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"ক্রেডিট কার্ডের নম্বর ও পাসওয়ার্ডগুলির মতো ব্যক্তিগত তথ্য অন্তর্ভুক্ত করে৷"</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"প্রদর্শনের বৃহত্তরীকরণ ব্যবস্থা নিয়ন্ত্রণ করুন"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"ডিসপ্লে বড়কার ব্যবস্থা নিয়ন্ত্রণ করুন"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"প্রদর্শনের জুমের স্তর এবং লোকেশন নির্ধারন নিয়ন্ত্রণ করুন৷"</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"অঙ্গভঙ্গির কাজগুলি সম্পাদন"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"আলতো চাপ দেওয়া, সোয়াইপ, পিঞ্চ করা এবং অন্যান্য ইঙ্গিতের কাজগুলি সম্পাদন করতে পারবেন৷"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"অফিস অ্যাপ চালু করবেন?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"আপনার অফিস অ্যাপ এবং বিজ্ঞপ্তিতে অ্যাক্সেস পান"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"জরুরি"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"আপনার অফিসের অ্যাপ এবং কলে অ্যাক্সেস পান"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 4bc3399..1e88766 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -325,20 +325,20 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupa podacima senzora o vašim vitalnim funkcijama"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavještenja"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikaz obavještenja"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"preuzima sadržaj prozora"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"preuzimati sadržaj prozora"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregleda sadržaj prozora koji trenutno koristite."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"uključi opciju Istraživanje dodirom"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Stavke koje dodirnete bit će izgovorene naglas, a ekran možete istraživati koristeći pokrete."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"prati tekst koji unosite"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"uključiti Istraživanje dodirom"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Stavke koje dodirnete će se izgovarati naglas i moći ćete istraživati ekran pomoću pokreta."</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"pratiti tekst koji unosite"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"kontrolira uvećavanje prikaza na ekranu"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrolira stepen uvećanja prikaza na ekranu i podešavanje položaja."</string>
- <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"izvodi pokrete"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"kontrolirati uvećavanje prikaza na ekranu"</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrolira nivo i položaj zumiranja na ekranu."</string>
+ <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"izvoditi pokrete"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Može dodirivati, prevlačiti, hvatati prstima i praviti druge pokrete."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"prepoznaje pokrete za otisak prsta"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Moguće je zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"pravi snimke ekrana"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Moguće je snimiti ekran."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"prepoznavati pokrete otiska prsta"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Može zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"praviti snimke ekrana"</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Može napraviti snimak ekrana."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"onemogućavanje ili mijenjanje statusne trake"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Dozvoljava aplikaciji onemogućavanje statusne trake ili dodavanje i uklanjanje sistemskih ikona."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"funkcioniranje u vidu statusne trake"</string>
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Uključiti poslovne aplikacije?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pristupite poslovnim aplikacijama i obavještenjima"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitan slučaj"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Ostvarite pristup poslovnim aplikacijama i pozivima"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b863fb5..5843095 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -326,19 +326,19 @@
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificacions"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostra notificacions"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contingut de la finestra"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecciona el contingut d\'una finestra amb què estàs interaccionant."</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspeccionar el contingut d\'una finestra amb què estàs interaccionant."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar Exploració tàctil"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Els elements que toquis es diran en veu alta, i podràs explorar la pantalla amb gestos."</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Els elements que toquis s\'enunciaran en veu alta, i la pantalla es pot explorar amb gestos."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Observar el text que escrius"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Inclou dades personals com ara números de targetes de crèdit i contrasenyes."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Controlar l\'ampliació de la pantalla"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controla el nivell i la posició del zoom de la pantalla."</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controlar el nivell i la posició del zoom de la pantalla."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Fer gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Permet tocar, lliscar, pinçar i fer altres gestos."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos d\'empremtes digitals"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Captura gestos realitzats en el sensor d\'empremtes digitals del dispositiu."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Fes una captura de pantalla"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Pots fer una captura de la pantalla."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Pot capturar els gestos fets en el sensor d\'empremtes digitals del dispositiu."</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Fer una captura de pantalla"</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Pot fer una captura de la pantalla."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"desactivar o modificar la barra d\'estat"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Permet que l\'aplicació desactivi la barra d\'estat o afegeixi i elimini icones del sistema."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"aparèixer a la barra d\'estat"</string>
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Activar aplicacions de treball?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Accedeix a les teves aplicacions i notificacions de treball"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergència"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Obtén accés a les teves trucades i aplicacions de treball"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 10b92c8..7e864a4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Zapnout pracovní aplikace?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Získejte přístup ke svým pracovním aplikacím a oznámením"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Stav nouze"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Získejte přístup ke svým pracovním aplikacím a hovorům"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index cae119d..29cb818 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vil du aktivere arbejdsapps?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Få adgang til dine arbejdsapps og notifikationer"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nødopkald"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Få adgang til dine arbejdsapps og opkald"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8d0d56a..29703a5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Geschäftliche Apps aktivieren?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Du erhältst Zugriff auf deine geschäftlichen Apps und Benachrichtigungen"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Notruf"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Zugriff auf deine geschäftlichen Apps und Anrufe anfordern"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index effa751..185308f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ενεργοπ. εφαρμογών εργασιών;"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Αποκτήστε πρόσβαση στις εφαρμογές εργασιών και τις ειδοποιήσεις"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ενεργοποίηση"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Έκτακτη ανάγκη"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Αποκτήστε πρόσβαση στις εφαρμογές εργασιών και τις κλήσεις"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a83ae5c..94bdb01 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Turn on work apps?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Get access to your work apps and notifications"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Get access to your work apps and calls"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c691bb2..b52f527 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Turn on work apps?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Get access to your work apps and notifications"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Get access to your work apps and calls"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7ec6567..dce46b4 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Turn on work apps?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Get access to your work apps and notifications"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Get access to your work apps and calls"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 22ccd22..93b4dc8 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"¿Activar apps de trabajo?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Obtén acceso a tus apps de trabajo y notificaciones"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergencia"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Obtén acceso a tus llamadas y apps de trabajo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f1f43cd..caefd2c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"¿Activar aplicaciones de trabajo?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Accede a tus aplicaciones y notificaciones de trabajo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergencia"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Consigue acceso a tus aplicaciones y llamadas de trabajo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index bb969ad..611c4c0 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Lülitada töörakendused sisse?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Hankige juurdepääs oma töörakendustele ja märguannetele"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hädaolukord"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Hankige juurdepääs oma töörakendustele ja kõnedele"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 78a5398..ccf7308 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -324,19 +324,19 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"atzitu bizi-konstanteei buruzko sentsorearen datuak"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Jakinarazpenak"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"jakinarazpenak erakutsi"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Eskuratu leihoko edukia"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Leihoko edukia eskuratu."</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Arakatu irekita daukazun leihoko edukia."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Aktibatu \"Arakatu ukituta\""</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\"Arakatu ukituta\" aktibatu."</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Sakatutako elementuak ozen irakurriko dira eta pantaila keinu bidez arakatu ahal izango da."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Behatu idazten duzun testua"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Idazten duzun testua behatu."</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Ez da salbuespenik egiten datu pertsonalekin, hala nola kreditu-txartelen zenbakiekin eta pasahitzekin."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Kontrolatu pantailaren zoom-maila"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrolatu pantailaren zoom-maila eta posizioa."</string>
- <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Egin keinuak"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Pantailaren zoom-maila kontrolatu."</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Pantailaren zoom-maila eta posizioa kontrolatu."</string>
+ <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Keinuak egin."</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Hatz-marken keinuak"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Gailuaren hatz-marken sentsorean egindako keinuak atzeman ditzake."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Atera pantaila-argazki bat"</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Pantaila-argazkiak atera."</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Pantaila-argazkiak atera ditzake."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"desgaitu edo aldatu egoera-barra"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Laneko aplikazioak aktibatu nahi dituzu?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Atzitu laneko aplikazioak eta jakinarazpenak"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Larrialdia"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Atzitu laneko aplikazioak eta deiak"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 9721cfc..8d0e8b1 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"برنامههای کاری روشن شود؟"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"دسترسی به اعلانها و برنامههای کاری"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"اضطراری"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"دسترسی به تماسها و برنامههای کاری"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a4b3568..f327cea 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Käytetäänkö työsovelluksia?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Palauta työsovellukset ja ilmoitukset käyttöön"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hätätilanne"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Palauta työsovellukset ja puhelut käyttöön"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 8cc239e..2019938 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Activer applis professionnelles?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Accédez à vos applications professionnelles et à vos notifications"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgence"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Demandez l\'accès à vos applications professionnelles et à vos appels"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index db14f84..b58d375 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Activer les applis pro ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Accéder à vos applis et notifications professionnelles"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgence"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Demandez l\'accès à vos applications professionnelles et à vos appels"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index e655e69..d998add 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Activar as apps do traballo?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Obtén acceso ás túas aplicacións e notificacións do traballo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emerxencia"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Obtén acceso ás túas chamadas e aplicacións do traballo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index feb3e9f..3be37c9 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"શું ઑફિસ માટેની ઍપ ચાલુ કરીએ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"તમારી ઑફિસ માટેની ઍપ અને નોટિફિકેશનનો ઍક્સેસ મેળવો"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ઇમર્જન્સી"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"તમારી ઑફિસ માટેની ઍપ અને કૉલનો ઍક્સેસ મેળવો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c6d26a2..06a7b5e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन चालू करने हैं?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"अपने ऑफ़िस के काम से जुड़े ऐप्लिकेशन और सूचनाओं का ऐक्सेस पाएं"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करें"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आपातकालीन कॉल"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"अपने वर्क ऐप्लिकेशन और कॉल का ऐक्सेस पाएं"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index b1a6153..135a7c70 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Uključiti poslovne aplikacije?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pristupite svojim poslovnim aplikacijama i obavijestima"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitni slučaj"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Pristupite svojim poslovnim aplikacijama i pozivima"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 951336c..c4a0a9b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Bekapcsolja a munkaappokat?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Hozzáférést kaphat munkahelyi alkalmazásaihoz és értesítéseihez"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Vészhelyzet"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Hozzáférést kaphat munkahelyi alkalmazásaihoz és hívásaihoz"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 29c1121..db6046c 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Միացնե՞լ հավելվածները"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Ձեզ հասանելի կդառնան ձեր աշխատանքային հավելվածներն ու ծանուցումները"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Արտակարգ իրավիճակ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Ստացեք ձեր աշխատանքային հավելվածների և զանգերի հասանելիություն"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d09926d..c22480a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Aktifkan aplikasi kerja?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Dapatkan akses ke aplikasi kerja dan notifikasi"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Darurat"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Dapatkan akses ke aplikasi kerja dan panggilan"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0057e19..eadd87c 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1708,8 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Litaleiðrétting"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhent stilling"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mjög dökkt"</string>
- <!-- no translation found for hearing_aids_feature_name (1125892105105852542) -->
- <skip />
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Heyrnartæki"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1944,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Kveikja á vinnuforritum?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Fá aðgang að vinnuforritum og tilkynningum"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Neyðartilvik"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Fá aðgang að vinnuforritum og símtölum"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4ba4b29..e0fa0f4 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Attivare le app di lavoro?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Attiva l\'accesso alle app di lavoro e alle notifiche"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergenza"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Richiedi l\'accesso alle app di lavoro e alle chiamate"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
<string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7bb43b0..e84252f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"להפעיל את האפליקציות לעבודה?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"קבלת גישה להתראות ולאפליקציות בפרופיל העבודה"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"הפעלה"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"שיחת חירום"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"קבלת גישה לשיחות ולאפליקציות בפרופיל העבודה"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 79bd6cb..c384e99 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"仕事用アプリを ON にしますか?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"仕事用のアプリを利用し、通知を受け取れるようになります"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"緊急通報"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"仕事用アプリを利用し、通話を行えるようになります"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"アプリの利用不可"</string>
<string name="app_blocked_message" msgid="542972921087873023">"現在 <xliff:g id="APP_NAME">%1$s</xliff:g> はご利用になれません。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>は利用できません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index f173973..5e96865 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"გსურთ სამსახურის აპების ჩართვა?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"თქვენი სამსახურის აპებსა და შეტყობინებებზე წვდომის მოპოვება"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ჩართვა"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"საგანგებო სიტუაცია"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"მოიპოვეთ წვდომა თქვენი სამსახურის აპებსა და ზარებზე"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"აპი მიუწვდომელია"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ამჟამად მიუწვდომელია."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> მიუწვდომელია"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b8aa264..eba758a 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -329,7 +329,7 @@
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Түртілген элементтерді дыбыстау функциясын қосу"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Түртілген элементтер дауыстап айтылады және экранды қимылдар арқылы зерттеуге болады."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Терілген мәтінді тексеру"</string>
- <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Несиелік карта нөмірі және құпия сөздер сияқты жеке деректі қоса."</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Несиелік карта нөмірлері және құпия сөздер сияқты жеке деректерді қамтиды."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Дисплей ұлғайтуды басқару"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Дисплейдің масштабтау деңгейін және орналастыруды басқару."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Қимылдарды орындау"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Жұмыс қолданбаларын қосасыз ба?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Жұмыс қолданбалары мен хабарландыруларына қол жеткізесіз."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Құтқару қызметіне қоңырау шалу"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Жұмыс қолданбаларын пайдаланып, қоңырауларды қабылдаңыз."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 44b6137..85247df 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -325,7 +325,7 @@
<string name="permgrouplab_notifications" msgid="5472972361980668884">"ការជូនដំណឹង"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"បង្ហាញការជូនដំណឹង"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ទាញយកខ្លឹមសារវិនដូ"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ពិនិត្យខ្លឹមសារវិនដូដែលអ្នកកំពុងទាក់ទងជាមួយ។"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ពិនិត្យខ្លឹមសារវិនដូដែលអ្នកកំពុងធ្វើអន្តរកម្មជាមួយ។"</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"បើកការរកមើលដោយប៉ះ"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"ធាតុដែលបានប៉ះនឹងត្រូវបានអានឮៗ ហើយអេក្រង់នោះអាចត្រូវបានស្វែងរកដោយប្រើកាយវិការ។"</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"មើលអត្ថបទដែលវាយ"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"បើកកម្មវិធីការងារឬ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ទទួលបានសិទ្ធិចូលប្រើការជូនដំណឹង និងកម្មវិធីការងាររបស់អ្នក"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"បើក"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ពេលមានអាសន្ន"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"សុំសិទ្ធិចូលប្រើប្រាស់កម្មវិធីការងារ និងការហៅរបស់អ្នក"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"មិនអាចប្រើកម្មវិធីនេះបានទេ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"មិនអាចប្រើ <xliff:g id="APP_NAME">%1$s</xliff:g> នៅពេលនេះបានទេ។"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1e2a5fa..2ad0200 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ಕೆಲಸ ಆ್ಯಪ್ಗಳನ್ನು ಆನ್ ಮಾಡಬೇಕೆ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ನಿಮ್ಮ ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಪಡೆಯಿರಿ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್ ಮಾಡಿ"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ತುರ್ತು"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"ನಿಮ್ಮ ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಕರೆಗಳಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಪಡೆಯಿರಿ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index dbcf849..ad429ba 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"직장 앱을 사용 설정하시겠습니까?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"직장 앱 및 알림에 액세스하세요."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"긴급 전화"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"직장 앱 및 전화 통화에 대한 액세스를 요청하세요."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index edb0886..d4c4c07 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -30,7 +30,7 @@
<string name="mmiError" msgid="2862759606579822246">"Туташууда көйгөй чыкты же MMI коду жараксыз."</string>
<string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функция колдоого алынбайт."</string>
<string name="mmiFdnError" msgid="3975490266767565852">"Иш-аракет туруктуу терүү номерлери менен гана чектелет."</string>
- <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Роуминг учурунда чалууну башка номерге багыттоонун жөндөөлөрүн телефонуңуздан өзгөртүү мүмкүн эмес."</string>
+ <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Роуминг учурунда чалууну башка номерге багыттоонун параметрлерин телефонуңуздан өзгөртүү мүмкүн эмес."</string>
<string name="serviceEnabled" msgid="7549025003394765639">"Кызмат иштетилди."</string>
<string name="serviceEnabledFor" msgid="1463104778656711613">"Кызмат төмөнкү үчүн иштетилди:"</string>
<string name="serviceDisabled" msgid="641878791205871379">"Кызмат өчүрүлдү."</string>
@@ -72,7 +72,7 @@
<string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"Номурду аныктоонун демейки абалы \"чектелбейт\" деп коюлган. Кийинки чалуу: Чектелген"</string>
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Номурду аныктоонун демейки абалы \"чектелбейт\" деп коюлган. Кийинки чалуу: Чектелбейт"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Кызмат камсыздалган эмес."</string>
- <string name="CLIRPermanent" msgid="166443681876381118">"Чалуучунун далдаштырма дайындары жөндөөлөрүн өзгөртө албайсыз."</string>
+ <string name="CLIRPermanent" msgid="166443681876381118">"Чалуучунун далдаштырма дайындары параметрлерин өзгөртө албайсыз."</string>
<string name="auto_data_switch_title" msgid="3286350716870518297">"Мобилдик Интернет <xliff:g id="CARRIERDISPLAY">%s</xliff:g> которулду"</string>
<string name="auto_data_switch_content" msgid="803557715007110959">"Бул функциянын параметрлерин \"Тууралоо\" бөлүмүнөн өзгөртө аласыз"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мобилдик Интернет кызматы жок"</string>
@@ -324,7 +324,7 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"организмдин абалына көз салган сенсордун дайындарына мүмкүнчүлүк алуу"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Билдирмелер"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"билдирмелерди көрсөтүү"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Терезедеги мазмунду алып турат"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Терезедеги нерселерди алып туруу"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Учурда ачылып турган терезедеги маалыматты талдайт."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\"Сыйпалап изилдөө\" мүмкүнчүлүгүн иштетет"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Басылып жаткан элементтерди айтып турат жана түзмөктү жаңсоолор менен башкаруу мүмкүнчүлүгүн иштетет."</string>
@@ -337,7 +337,7 @@
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Манжа изинин жаңсоолору"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Түзмөктөгү манжа изинин сенсорунда жасалган жаңсоолорду жаздырып алат."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Скриншот тартып алуу"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Дисплейдин скриншотун тартып алууга болот."</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Дисплейдин скриншотун тартып алсаңыз болот."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"абал тилкесин өчүрүү же өзгөртүү"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Колдонмого абал тилкесин өчүрүү же тутум сүрөтчөлөрүн кошуу же алып салуу мүмкүнчүлүгүн берет."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"абал тилкесинин милдетин аткаруу"</string>
@@ -431,7 +431,7 @@
<string name="permlab_getPackageSize" msgid="375391550792886641">"колдонмо сактагычынын мейкиндигин өлчөө"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"Колдонмого өз кодун, дайындарын жана кэш өлчөмдөрүн түшүрүп алуу мүмкүнчүлүгүн берет"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"система тууралоолорун өзгөртүү"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"Колдонмого системанын коопсуздук жөндөөлөрүнүн дайындарын өзгөртүү мүмкүнчүлүгүн берет. Кесепттүү колдонмолор тутумуңуздун конфигурациясын бузуп салышы мүмкүн."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"Колдонмого системанын коопсуздук параметрлеринин дайындарын өзгөртүү мүмкүнчүлүгүн берет. Кесепттүү колдонмолор тутумуңуздун конфигурациясын бузуп салышы мүмкүн."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"түзмөктү жандырганда иштеп баштоо"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Колдонмого тутум жүктөлүп бүтөөрү менен өзүн-өзү иштетүү мүмкүнчүлүгүн берет. Бул планшеттин ишке киргизилишин кыйла создуктуруп, планшеттин үзгүлтүксүз иштешин жайлатып салышы мүмкүн."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Тутум күйгүзүлөрү менен колдонмого өз алдынча иштеп баштоого уруксат берет. Ага байланыштуу Android TV түзмөгүңүз кечирээк күйгүзүлүп, ошондой эле колдонмо такай иштеп тургандыктан, түзмөк жайыраак иштеп калышы мүмкүн."</string>
@@ -474,7 +474,7 @@
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Колдонмо кайда жүргөнүңүздү активдүү режимде гана болжолдуу аныктай алат. Ал үчүн түзмөгүңүздө жайгашкан жерди аныктоо кызматын иштетишиңиз керек."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"жайгашкан жерди фондо аныктоо"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Колдонмо кайда жүргөнүңүздү активдүү режимде гана эмес, фондук режимде да аныктай алат."</string>
- <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"аудио жөндөөлөрүңүздү өзгөртүңүз"</string>
+ <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"аудио параметрлериңизди өзгөртүңүз"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Колдонмого үн деңгээли жана кайсы динамик аркылуу үн чыгарылышы керек сыяктуу түзмөктүн аудио тууралоолорун өзгөртүүгө уруксат берет."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"аудио жаздыруу"</string>
<string name="permdesc_recordAudio" msgid="5857246765327514062">"Бул колдонмо иштеп жатканда микрофон менен аудио файлдарды жаздыра алат."</string>
@@ -719,7 +719,7 @@
</string-array>
<string name="face_error_vendor_unknown" msgid="7387005932083302070">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string>
- <string name="permlab_readSyncSettings" msgid="6250532864893156277">"шайкештирүү жөндөөлөрүн окуу"</string>
+ <string name="permlab_readSyncSettings" msgid="6250532864893156277">"шайкештирүү параметрлерин окуу"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"синхрондоштурууну өчүрүү/жандыруу"</string>
<string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Колдонмого эсеп менен синхрондошуу тууралоолорун өзгөртүү уруксатын берет. Мисалы, бул Кишилер колдонмосун эсеп менен синхрондошуусун иштете алат."</string>
@@ -1226,7 +1226,7 @@
<string name="launch_warning_original" msgid="3332206576800169626">"Башында <xliff:g id="APP_NAME">%1$s</xliff:g> жүргүзүлгөн."</string>
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"Ар дайым көрүнсүн"</string>
- <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Муну тутум жөндөөлөрүнөн кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</string>
+ <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Муну тутум параметрлеринен кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</string>
<string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу көрүнүштүн тандалган өлчөмүн экранда көрсөтө албайт жана туура эмес иштеши мүмкүн."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"Ар дайым көрүнсүн"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> Android OS тутуму менен иштеген түзмөктүн шайкеш келбеген версиясы үчүн орнотулган колдонмо жана туура эмес иштеши мүмкүн. Колдонмонун жаңырган версиясы жеткиликтүү болушу мүмкүн."</string>
@@ -1495,7 +1495,7 @@
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"Туташты"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"Ар дайым иштеген VPN\'ден ажыратуу"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"Ар дайым күйүк VPN\'ге туташпай калды"</string>
- <string name="vpn_lockdown_config" msgid="8331697329868252169">"Тармакты же VPN жөндөөлөрүн өзгөртүү"</string>
+ <string name="vpn_lockdown_config" msgid="8331697329868252169">"Тармакты же VPN параметрлерин өзгөртүү"</string>
<string name="upload_file" msgid="8651942222301634271">"Файл тандоо"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"Эч файл тандалган жок"</string>
<string name="reset" msgid="3865826612628171429">"Баштапкы абалга келтирүү"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Жумуш колдонмолору күйгүзүлсүнбү?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Жумуш колдонмолоруңузга жана билдирмелериңизге мүмкүнчүлүк алыңыз"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Шашылыш чалуу"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Жумуш колдонмолоруңузга жана чалууларыңызга мүмкүнчүлүк алыңыз"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
@@ -2066,7 +2064,7 @@
<string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Көбүрөөк маалымат алып, өзгөртүү үчүн таптаңыз."</string>
<string name="zen_upgrade_notification_title" msgid="8198167698095298717">"\"Тынчымды алба\" режими өзгөрдү"</string>
<string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Бөгөттөлгөн нерселерди көрүү үчүн таптаңыз."</string>
- <string name="review_notification_settings_title" msgid="5102557424459810820">"Билдирмелердин жөндөөлөрүн карап чыгуу"</string>
+ <string name="review_notification_settings_title" msgid="5102557424459810820">"Билдирмелердин параметрлерин карап чыгуу"</string>
<string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 версиясынан баштап билдирмелерди жөнөтүү үчүн орноткон колдонмолоруңузга уруксат берүү керек. Учурдагы колдонмолор үчүн бул уруксатты өзгөртүү үчүн таптап коюңуз."</string>
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Кийинчерээк эскертүү"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Жабуу"</string>
@@ -2272,7 +2270,7 @@
<string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
<string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
<string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
- <string name="window_magnification_prompt_title" msgid="2876703640772778215">"Чоңойтуу функциясынын жаңы жөндөөлөрү"</string>
+ <string name="window_magnification_prompt_title" msgid="2876703640772778215">"Чоңойтуу функциясынын жаңы параметрлери"</string>
<string name="window_magnification_prompt_content" msgid="8159173903032344891">"Эми экрандын бир бөлүгүн чоңойто аласыз"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Жөндөөлөрдөн күйгүзүү"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Жабуу"</string>
@@ -2283,7 +2281,7 @@
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Сенсордун купуялыгы"</string>
<string name="splash_screen_view_icon_description" msgid="180638751260598187">"Колдонмонун сүрөтчөсү"</string>
<string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Колдонмонун брендинин сүрөтү"</string>
- <string name="view_and_control_notification_title" msgid="4300765399209912240">"Кирүү мүмкүнчүлүгүнүн жөндөөлөрүн текшериңиз"</string>
+ <string name="view_and_control_notification_title" msgid="4300765399209912240">"Кирүү мүмкүнчүлүгүнүн параметрлерин текшериңиз"</string>
<string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> экраныңызды көрүп, көзөмөлдөй алат. Көрүү үчүн таптап коюңуз."</string>
<string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"Билдирүү (<xliff:g id="MESSAGE">%1$s</xliff:g>) которулду."</string>
<string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Билдирүү <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> тилинен <xliff:g id="TO_LANGUAGE">%2$s</xliff:g> тилине которулду."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 1874d27..13a88ca 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ເປີດໃຊ້ແອັບບ່ອນເຮັດວຽກບໍ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ຮັບສິດເຂົ້າເຖິງແອັບບ່ອນເຮັດວຽກ ແລະ ການແຈ້ງເຕືອນຂອງທ່ານ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ເປີດ"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ສຸກເສີນ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"ຮັບສິດເຂົ້າເຖິງແອັບບ່ອນເຮັດວຽກ ແລະ ການໂທຂອງທ່ານ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ແອັບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b0c481e..6a66751 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Įjungti darbo programas?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pasiekite darbo programas ir pranešimus"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Pagalbos tarnyba"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Pasiekite darbo programas ir skambučius"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3aca9f8..2bb12db 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vai ieslēgt darba lietotnes?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Iegūstiet piekļuvi darba lietotnēm un paziņojumiem"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Ārkārtas zvans"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Iegūstiet piekļuvi darba lietotnēm un zvaniem"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 28d5969..52019e4 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -324,20 +324,20 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"пристапува до податоците од сензорите за виталните знаци"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Известувања"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"да прикажува известувања"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Преземе содржина на прозорец"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Ја следи содржината на прозорецот со кој се комуницира."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Вклучи „Истражувај со допир“"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Допрените ставки ќе се изговорат на глас и екранот може да се истражува со движења."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Го следи напишаниот текст"</string>
- <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Опфаќа лични податоци како што се броеви на кредитни картички и лозинки."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Го контролира зголемувањето на екранот"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Го контролира нивото на зумирање и позиционирање на екранот."</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"да ги вчитува содржините од прозорците"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"да ги проверува содржините од прозорецот што го користите"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"да вклучи „Истражувај со допир“"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"допрените ставки ќе се изговараат наглас и екранот ќе може да се истражува со движења"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"да го следи текстот што го пишувате"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"вклучително и лични податоци како што се броеви на кредитни картички и лозинки"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"да го контролира зголемувањето на екранот"</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"да го контролира нивото на зумирање и позиционирањето на екранот"</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Користете движења"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Може да допрете, повлечете, штипнете и да користите други движења."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Движења за отпечатоци"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Може да сними движења што се направени на сензорот за отпечатоци на уредот."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Зачувување слика од екранот"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Може да направи слика од екранот."</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Може да зачува слика од екранот."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"оневозможи или измени статусна лента"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Дозволува апликацијата да ја оневозможи статусната лента или да додава или отстранува системски икони."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"да стане статусна лента"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Да се вклучат работни апликации?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Добијте пристап до вашите работни апликации и известувања"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Вклучи"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Итен случај"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Добијте пристап до вашите работни апликации и повици"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 4076c68..88ce780 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കണോ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"നിങ്ങളുടെ ഔദ്യോഗിക ആപ്പുകളിലേക്കും അറിയിപ്പുകളിലേക്കും ആക്സസ് നേടുക"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ഓണാക്കുക"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"അടിയന്തരം"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"നിങ്ങളുടെ ഔദ്യോഗിക ആപ്പുകളിലേക്കും കോളുകളിലേക്കും ആക്സസ് നേടുക"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 28fa200..0dc530d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ажлын аппуудыг асаах уу?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Ажлын аппууд болон мэдэгдлүүддээ хандах эрх аваарай"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Асаах"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Яаралтай тусламж"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Ажлын аппууд болон дуудлагууддаа хандах эрх аваарай"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d0d9da3..1b899a5 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"कार्य अॅप्स सुरू करायची का?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"तुमची कार्य ॲप्स आणि सूचना यांचा अॅक्सेस मिळवा"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"सुरू करा"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आणीबाणी"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"तुमची कार्य ॲप्स आणि कॉल यांचा अॅक्सेस मिळवा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 3c0675b..7419995 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Hidupkan apl kerja?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Dapatkan akses kepada apl kerja dan pemberitahuan anda"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Kecemasan"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Dapatkan akses kepada apl kerja dan panggilan anda"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9c1f5ff..8d78806 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"အလုပ်သုံးအက်ပ်များ ဖွင့်မလား။"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"သင့်အလုပ်သုံးအက်ပ်နှင့် အကြောင်းကြားချက်များသုံးခွင့် ရယူပါ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ဖွင့်ရန်"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"အရေးပေါ်"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"သင်၏ အလုပ်သုံးအက်ပ်နှင့် ခေါ်ဆိုမှုများကို ဝင်ခွင့်တောင်းဆိုပါ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 1d231fe..1835ceb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vil du slå på jobbapper?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Få tilgang til jobbapper og -varsler"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nød"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Få tilgang til jobbapper og -samtaler"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 54c24b5..9492433 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -330,8 +330,8 @@
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"ट्याप गरिएका वस्तुहरू चर्को स्वरमा बोलिने छन् र इसाराहरूको प्रयोग गरेर स्क्रिनमा अन्वेषण गर्न सकिन्छ।"</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"आफुले टाइप गरेको पाठको निरीक्षण गर्नुहोस्"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"व्यक्तिगत डेटा जस्तै क्रेडिट कार्ड नम्बरहरू र पासवर्डहरू समावेश गर्दछ।"</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"प्रदर्शन आवर्धन नियन्त्रण गर्नुहोस्"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"प्रदर्शनको जुम स्तर र स्थिति नियन्त्रण गर्नुहोस्।"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"डिस्प्ले म्याग्निफिकेसन नियन्त्रण गर्नुहोस्"</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"डिस्प्लेको जुम लेबल र स्थिति नियन्त्रण गर्नुहोस्।"</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"इसाराहरू सम्बन्धी कार्य गर्नुहोस्"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ट्याप, स्वाइप गर्न, थिच्न र अन्य इसाराहरू सम्बन्धी कार्य गर्न सक्छ"</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"फिंगरप्रिन्टका इसाराहरू"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"कामसम्बन्धी एपहरू अन गर्ने हो?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"कामसम्बन्धी एप चलाउने र सूचना प्राप्त गर्ने सुविधा अन गर्नुहोस्"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"अन गर्नुहोस्"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आपत्कालीन"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"कामसम्बन्धी एप चलाउने र कल प्राप्त गर्ने सुविधा अन गर्नुहोस्"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index da34559..8de5fe4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -228,7 +228,7 @@
<string name="shutdown_progress" msgid="5017145516412657345">"Uitzetten…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Je tablet wordt uitgezet."</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Je Android TV-apparaat wordt uitgezet."</string>
- <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Je horloge wordt uitgezet."</string>
+ <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Je smartwatch wordt uitgezet."</string>
<string name="shutdown_confirm" product="default" msgid="136816458966692315">"Je telefoon wordt uitgezet."</string>
<string name="shutdown_confirm_question" msgid="796151167261608447">"Wil je afsluiten?"</string>
<string name="reboot_safemode_title" msgid="5853949122655346734">"Opnieuw opstarten in veilige modus"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Werk-apps aanzetten?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Krijg toegang tot je werk-apps en meldingen"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aanzetten"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Noodgeval"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Krijg toegang tot je werk-apps en gesprekken"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 5cb0b9d..2dc96a7 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ୱାର୍କ ଆପ୍ସ ଚାଲୁ କରିବେ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ଆପଣଙ୍କ ୱାର୍କ ଆପ୍ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ ପାଆନ୍ତୁ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ଚାଲୁ କରନ୍ତୁ"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ଜରୁରୀକାଳୀନ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"ଆପଣଙ୍କ ୱାର୍କ ଆପ୍ସ ଏବଂ କଲଗୁଡ଼ିକୁ ଆକ୍ସେସ ପାଆନ୍ତୁ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index de05d46..a2f3b11 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -324,7 +324,7 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"ਆਪਣੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਚਿੰਨ੍ਹਾਂ ਬਾਰੇ ਸੰਵੇਦਕ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"ਸੂਚਨਾਵਾਂ"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ਵਿੰਡੋ ਸਮੱਗਰੀ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰਨਾ"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ਵਿੰਡੋ ਸਮੱਗਰੀ ਮੁੜ-ਪ੍ਰਾਪਤ ਕਰਨਾ"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ਉਸ ਵਿੰਡੋ ਸਮੱਗਰੀ ਦੀ ਜਾਂਚ ਕਰੋ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਅੰਤਰਕਿਰਿਆ ਕਰ ਰਹੇ ਹੋ"</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\'ਸਪੱਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ ਕਰੋ\' ਚਾਲੂ ਕਰਨਾ"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"ਟੈਪ ਕੀਤੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਉੱਚੀ ਆਵਾਜ਼ ਵਿੱਚ ਬੋਲਿਆ ਜਾਵੇਗਾ ਅਤੇ ਸਕ੍ਰੀਨ ਦੀ ਸੰਕੇਤਾਂ ਦੀ ਵਰਤੋਂ ਨਾਲ ਪੜਚੋਲ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਚਾਲੂ ਕਰਨੀਆਂ ਹਨ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ਆਪਣੀਆਂ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ਐਮਰਜੈਂਸੀ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"ਆਪਣੀਆਂ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਅਤੇ ਕਾਲਾਂ ਤੱਕ ਪਹੁੰਚ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9e0269b..d0857f5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Włączyć aplikacje służbowe?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Uzyskaj dostęp do służbowych aplikacji i powiadomień"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Połączenie alarmowe"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Uzyskaj dostęp do służbowych aplikacji i połączeń"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ce1f686..8c03ed9 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ativar apps de trabalho?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Acesse seus apps e notificações de trabalho"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Acesse seus apps e ligações de trabalho"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 66bd560..fc91fb4 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ativar as apps de trabalho?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Obtenha acesso às suas apps de trabalho e notificações"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Obtenha acesso às suas apps de trabalho e chamadas"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ce1f686..8c03ed9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ativar apps de trabalho?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Acesse seus apps e notificações de trabalho"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Acesse seus apps e ligações de trabalho"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9663982..77206a1 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Activezi aplicațiile pentru lucru?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Obține acces la aplicațiile și notificările pentru lucru"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activează"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgență"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Solicită acces la aplicațiile și apelurile pentru lucru"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ba548b3..650fc71 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Включить рабочие приложения?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Вы получите доступ к рабочим приложениям и уведомлениям"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включить"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Экстренный вызов"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Получите доступ к рабочим приложениям и звонкам."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 0363b0d..d686d82 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"කාර්යාල යෙදු. ක්රියා. කරන්නද?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"ඔබගේ කාර්යාල යෙදුම් සහ දැනුම්දීම් වෙත ප්රවේශය ලබා ගන්න"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ක්රියාත්මක කරන්න"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"හදිසි අවස්ථාව"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"ඔබේ කාර්යාල යෙදුම් සහ ඇමතුම් වෙත ප්රවේශය ලබා ගන්න"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e84bc83..123b63c4 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -331,7 +331,7 @@
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Zapnúť funkciu Preskúmanie dotykom"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Po klepnutí na položku sa vysloví jej názov a obrazovku je možné preskúmať pomocou gest."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Sledovať zadávaný text"</string>
- <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Sledovanie zahŕňa osobné údaje ako sú čísla kreditných kariet a heslá."</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Sledovanie zahŕňa osobné údaje, ako sú čísla kreditných kariet a heslá."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Ovládať priblíženie obrazovky"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Ovládajte umiestnenie a úroveň priblíženia obrazovky."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Gestá"</string>
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Zapnúť pracovné aplikácie?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Získajte prístup k svojim pracovným aplikáciám a upozorneniam"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Zavolať na tiesňovú linku"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Získajte prístup k svojim pracovným aplikáciám a hovorom"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 52bef0b..ce19c52 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vklop delovnih aplikacij?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pridobite dostop do delovnih aplikacij in obvestil za delovni profil."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vklopi"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nujni primer"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Zagotovite si dostop do delovnih aplikacij in klicev."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index d691fd0..4964349 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -324,20 +324,20 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"qasu tek të dhënat e sensorëve rreth shenjave të tua jetësore"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Njoftimet"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"shfaq njoftimet"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Nxjerrë përmbajtjen e dritares"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Të nxjerrë përmbajtjen e dritares"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspekton përmbajtjen e dritares me të cilën po ndërvepron."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Aktivizojë funksionin \"Eksploro me prekje\""</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Të aktivizojë veçorinë \"Eksploro me prekje\""</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Artikujt e trokitur do të lexohen me zë të lartë dhe ekrani mund të eksplorohet duke përdorur gjestet."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Vëzhgojë tekstin që shkruan"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Të vëzhgojë tekstin që shkruan"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Përfshin të dhëna personale, si numrat e kartave të kreditit dhe fjalëkalimet."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Kontrollo zmadhimin e ekranit"</string>
- <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrollo nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Të kontrollojë zmadhimin e ekranit"</string>
+ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrollon nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Kryen gjeste"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gjestet e gjurmës së gishtit"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Mund të regjistrojë gjestet e kryera në sensorin e gjurmës së gishtit të pajisjes."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Nxirr një pamje të ekranit"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Mund të nxirret një pamje e ekranit."</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Mund të nxjerrë një pamje e ekranit."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"çaktivizo ose modifiko shiritin e statusit"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"të bëhet shiriti i statusit"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Të aktivizohen aplikacionet e punës?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Merr qasje tek aplikacionet e punës dhe njoftimet e tua"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgjenca"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Merr qasje tek aplikacionet e punës dhe telefonatat e tua"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index aab16eb..914e36c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1944,10 +1944,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Укључујете пословне апликације?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Приступајте пословним апликацијама и обавештењима"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Хитан случај"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Приступајте пословним апликацијама и позивима"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 125999b..c45c847 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -337,7 +337,7 @@
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Fingeravtrycksrörelser"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan registrera rörelser som utförs med hjälp av enhetens fingeravtryckssensor."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ta skärmbild"</string>
- <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Du kan ta en skärmbild av skärmen."</string>
+ <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Kan ta en skärmbild av skärmen."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"inaktivera eller ändra statusfält"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Tillåter att appen inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"visas i statusfältet"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vill du aktivera jobbappar?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Få åtkomst till jobbappar och aviseringar"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nödsituation"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Få åtkomst till jobbappar och samtal"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5cf2f77..cc7aa19 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Iwashe programu za kazini?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pata uwezo wa kufikia arifa na programu zako za kazini"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Simu za dharura"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Pata uwezo wa kufikia simu na programu zako za kazini"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 8f576ab..149f895 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -328,7 +328,7 @@
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"நீங்கள் பணியாற்றிக் கொண்டிருக்கும் சாளரத்தின் உள்ளடக்கத்தைப் பார்க்கலாம்."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"தொடுவதன் மூலம் அறிவதை இயக்கும்"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"தட்டிய உள்ளடக்கம் சத்தமாகப் படிக்கப்படும், சைகைகளைப் பயன்படுத்தி திரையில் உலாவலாம்."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"நீங்கள் தட்டச்சு செய்யும் உரையைக் கவனிக்கும்"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"நீங்கள் டைப் செய்யும் வார்த்தையைக் கவனிக்கும்."</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"கிரெடிட் கார்டு எண்கள் மற்றும் கடவுச்சொற்கள் போன்ற தனிப்பட்ட தகவலும் உள்ளடங்கும்."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"திரை பெரிதாவதைக் கட்டுப்படுத்தும்"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"திரையின் ஜூம் அளவையும் நிலையையும் கட்டுப்படுத்தலாம்."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"பணி ஆப்ஸை இயக்கவா?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"உங்கள் பணி ஆப்ஸுக்கும் அறிவிப்புகளுக்குமான அணுகலைப் பெறுங்கள்"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"இயக்கு"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"அவசர அழைப்பு"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"உங்கள் பணி ஆப்ஸுக்கும் அழைப்புகளுக்குமான அணுகலைப் பெறுங்கள்"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3cf745b..709be1a 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -326,7 +326,7 @@
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"నోటిఫికేషన్లను చూపండి"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"విండో కంటెంట్ను తిరిగి పొందుతుంది"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"మీరు పరస్పర చర్య చేస్తున్న విండో కంటెంట్ను పరిశీలిస్తుంది."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"తాకడం ద్వారా విశ్లేషణను ప్రారంభిస్తుంది"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"తాకడం ద్వారా విశ్లేషణను ఆన్ చేయండి"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"నొక్కిన అంశాలు బిగ్గరగా చదివి వినిపించబడతాయి మరియు సంజ్ఞలను ఉపయోగించి స్క్రీన్ను విశ్లేషించవచ్చు."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"మీరు టైప్ చేస్తున్న వచనాన్ని పరిశీలిస్తుంది"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"క్రెడిట్ కార్డు నంబర్లు మరియు పాస్వర్డ్ల వంటి వ్యక్తిగత డేటాను కలిగి ఉంటుంది."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"వర్క్ యాప్లను ఆన్ చేయాలా?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"మీ వర్క్ యాప్లు, నోటిఫికేషన్లకు యాక్సెస్ను పొందండి"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ఆన్ చేయి"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ఎమర్జెన్సీ"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"మీ వర్క్ యాప్లు, కాల్స్కు యాక్సెస్ను పొందండి"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"యాప్ అందుబాటులో లేదు"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> అందుబాటులో లేదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4afe454..3d46e4d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"เปิดแอปงานใช่ไหม"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"รับสิทธิ์เข้าถึงแอปงานและการแจ้งเตือนต่างๆ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"เปิด"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ฉุกเฉิน"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"รับสิทธิ์เข้าถึงแอปงานและการโทร"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e808d56..ff08592 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"I-on ang app para sa trabaho?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Makakuha ng access sa iyong mga app para sa trabaho at notification"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Makakuha ng access sa iyong mga app para sa trabaho at tawag"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 5d471b3..79ba5b5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"İş uygulamaları açılsın mı?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"İş uygulamalarınıza ve bildirimlerinize erişin"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Acil durum"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"İş uygulamalarınıza ve telefon aramalarınıza erişin"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 1620c8f..cd8762f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -329,7 +329,7 @@
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Отримувати вміст вікна"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Перевіряти вміст вікна, з яким ви взаємодієте."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Увімкнути функцію дослідження дотиком"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Активувати голосові підказки для елементів, яких торкаються, і користуватися інтерфейсом за допомогою жестів."</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Озвучувати елементи, яких торкаються, і здійснювати навігацію екраном за допомогою жестів."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Переглядати текст, який ви вводите"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Включає особисті дані, як-от номери кредитних карток і паролі."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Контролювати збільшення екрана"</string>
@@ -1945,10 +1945,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Увімкнути робочі додатки?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Отримайте доступ до своїх робочих додатків і сповіщень"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Увімкнути"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Екстрений виклик"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Отримайте доступ до своїх робочих додатків і дзвінків"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2b5b2f1..88cf716 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"ورک ایپس آن کریں؟"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"اپنی ورک ایپس اور اطلاعات تک رسائی حاصل کریں"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"آن کریں"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ایمرجنسی"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"اپنی ورک ایپس اور کالز تک رسائی حاصل کریں"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ایپ دستیاب نہیں ہے"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 258d4ce..eeb799f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -326,7 +326,7 @@
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"hiển thị thông báo"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Truy xuất nội dung cửa sổ"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Kiểm tra nội dung của cửa sổ bạn đang tương tác."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Bật Khám phá bằng cách chạm"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Bật tính năng Khám phá bằng cách chạm"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Đọc to các mục được nhấn và cho phép khám phá màn hình bằng cử chỉ."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Quan sát nội dung bạn nhập"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Bao gồm dữ liệu cá nhân chẳng hạn như số thẻ tín dụng và mật khẩu."</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Bật các ứng dụng công việc?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Bạn sẽ có quyền truy cập vào các ứng dụng công việc và thông báo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Khẩn cấp"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Hãy lấy quyền cập vào ứng dụng công việc và cuộc gọi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9b998c1..820d692 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"要开启工作应用访问权限吗?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"获取工作应用和通知的访问权限"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"开启"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"紧急呼叫"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"获取工作应用和通话的访问权限"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"应用无法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前无法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 065968c..b0e5f60 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"要開啟工作應用程式存取權嗎?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"開啟工作應用程式和通知的存取權"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"撥打緊急電話"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"要求存取工作應用程式和通話"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index fd94101..79b8bce 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -280,7 +280,7 @@
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN 狀態"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"來自 IT 管理員的快訊"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"快訊"</string>
- <string name="notification_channel_retail_mode" msgid="3732239154256431213">"零售商示範模式"</string>
+ <string name="notification_channel_retail_mode" msgid="3732239154256431213">"零售商展示模式"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"USB 連線"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"應用程式執行中"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"正在耗用電量的應用程式"</string>
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"要開啟工作應用程式存取權嗎?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"開啟工作應用程式和通知的存取權"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"撥打緊急電話"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"要求存取工作應用程式和通話"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2d17ae2..55b5e9a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1943,10 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Vula ama-app okusebenza womsebenzi?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Thola ukufinyelela kuma-app akho womsebenzi kanye nezaziso"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string>
- <!-- no translation found for work_mode_emergency_call_button (6818855962881612322) -->
- <skip />
- <!-- no translation found for work_mode_dialer_off_message (2193299184850387465) -->
- <skip />
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Isimo esiphuthumayo"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Thola ukufinyelela kuma-app akho womsebenzi kanye namakholi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 22d741c..826624a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3765,6 +3765,9 @@
{@link android.inputmethodservice.InputMethodService#onFinishInput()}.
-->
<attr name="supportsStylusHandwriting" format="boolean" />
+ <!-- Class name of an activity that allows the user to modify the stylus handwriting
+ settings for this service -->
+ <attr name="stylusHandwritingSettingsActivity" format="string" />
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index be22095..f544feb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -465,6 +465,12 @@
<string-array translatable="false" name="config_cdma_dun_supported_types">
</string-array>
+ <!-- Package name of the system app that implements the shared connectivity service -->
+ <string translatable="false" name="sharedconnectivity_service_package"></string>
+
+ <!-- Class name in the system app that implements the shared connectivity service -->
+ <string translatable="false" name="sharedconnectivity_service_class"></string>
+
<!-- Flag indicating whether we should enable the automatic brightness.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
@@ -4601,6 +4607,12 @@
<!-- Component name for the default module metadata provider on this device -->
<string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string>
+ <!-- Package name for the default Health Connect app.
+ OEMs can set this with their own health app package name to define a default app with high
+ priority for the app to store the health data. If set the app always has priority of 1
+ unless it is changed by the user. -->
+ <string name="config_defaultHealthConnectApp" translatable="false"></string>
+
<!-- This is the default launcher package with an activity to use on secondary displays that
support system decorations.
This launcher package must have an activity that supports multiple instances and has
@@ -6166,6 +6178,12 @@
<item>@string/config_mainDisplayShape</item>
<item>@string/config_secondaryDisplayShape</item>
</string-array>
+
+ <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner
+ permission for staging HealthConnect's remote data. The digest should be computed over the
+ DER encoding of the trusted certificate using the SHA-256 digest algorithm. -->
+ <string-array name="config_healthConnectStagingDataKnownSigners">
+ </string-array>
<!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner Health
Connect Migration permissions. The digest should be computed over the DER encoding of the
trusted certificate using the SHA-256 digest algorithm. -->
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 925b5d3..d40adf5 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -140,10 +140,4 @@
only single logical modem, by using its data connection in addition to cellular IMS. -->
<bool name="config_enable_virtual_dsda">false</bool>
<java-symbol type="bool" name="config_enable_virtual_dsda" />
-
- <!-- Whether to enable getSubscriptionUserHandle() api.
- If the value is true, return user handle associated with the subscription.
- If the value is set to false, return null. -->
- <bool name="config_enable_get_subscription_user_handle">true</bool>
- <java-symbol type="bool" name="config_enable_get_subscription_user_handle" />
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index f4b49e6..58b8601 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -128,6 +128,7 @@
<public name="isCredential"/>
<public name="searchResultHighlightColor" />
<public name="focusedSearchResultHighlightColor" />
+ <public name="stylusHandwritingSettingsActivity" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01cd0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2715c94..38336e4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -341,6 +341,7 @@
<java-symbol type="bool" name="config_checkWallpaperAtBoot" />
<java-symbol type="string" name="config_wallpaperManagerServiceName" />
<java-symbol type="string" name="config_inputEventCompatProcessorOverrideClassName" />
+ <java-symbol type="string" name="config_defaultHealthConnectApp" />
<java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="bool" name="config_enableScreenshotChord" />
<java-symbol type="bool" name="config_enableWifiDisplay" />
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
index f807bad..75f8c95 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
@@ -22,19 +22,22 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.ArraySet;
-import androidx.test.InstrumentationRegistry;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -48,10 +51,11 @@
@RunWith(MockitoJUnitRunner.class)
public final class ProgramListTest {
- public final Context mContext = InstrumentationRegistry.getContext();
+ private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
private static final int CREATOR_ARRAY_SIZE = 3;
- private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 500);
+ private static final int TIMEOUT_MS = 500;
+ private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(TIMEOUT_MS);
private static final boolean IS_PURGE = false;
private static final boolean IS_COMPLETE = true;
@@ -95,6 +99,7 @@
command.run();
}
};
+ private final ApplicationInfo mApplicationInfo = new ApplicationInfo();
private RadioTuner mRadioTuner;
private ITunerCallback mTunerCallback;
@@ -103,6 +108,8 @@
private ProgramList.ListCallback[] mListCallbackMocks;
private ProgramList.OnCompleteListener[] mOnCompleteListenerMocks;
@Mock
+ private Context mContextMock;
+ @Mock
private IRadioService mRadioServiceMock;
@Mock
private ITuner mTunerMock;
@@ -268,6 +275,18 @@
}
@Test
+ public void getProgramList_forTunerAdapterWhenListNotReady_fails() throws Exception {
+ Map<String, String> parameters = Map.of("ParameterKeyMock", "ParameterValueMock");
+ createRadioTuner();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class,
+ () -> mRadioTuner.getProgramList(parameters));
+
+ assertWithMessage("Exception for getting program list when not ready")
+ .that(thrown).hasMessageThat().contains("Program list is not ready yet");
+ }
+
+ @Test
public void getProgramList_forTunerAdapterWhenServiceDied_fails() throws Exception {
Map<String, String> parameters = Map.of("ParameterKeyMock", "ParameterValueMock");
createRadioTuner();
@@ -290,6 +309,19 @@
}
@Test
+ public void getDynamicProgramList_forTunerNotSupportingProgramList_returnsNull()
+ throws Exception {
+ createRadioTuner();
+ doThrow(new UnsupportedOperationException())
+ .when(mTunerMock).startProgramListUpdates(any());
+
+ ProgramList nullProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+
+ assertWithMessage("Exception for radio HAL client not supporting program list")
+ .that(nullProgramList).isNull();
+ }
+
+ @Test
public void getDynamicProgramList_forTunerAdapterWithServiceDied_throwsException()
throws Exception {
createRadioTuner();
@@ -346,7 +378,7 @@
mTunerCallback.onProgramListUpdated(FM_ADD_INCOMPLETE_CHUNK);
- verify(mOnCompleteListenerMocks[0], CALLBACK_TIMEOUT.times(0)).onComplete();
+ verify(mOnCompleteListenerMocks[0], after(TIMEOUT_MS).never()).onComplete();
}
@Test
@@ -367,6 +399,22 @@
}
@Test
+ public void onProgramListUpdated_afterProgramListClosed_notInvokeMockedCallbacks()
+ throws Exception {
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+ registerListCallbacks(/* numCallbacks= */ 1);
+ addOnCompleteListeners(/* numListeners= */ 1);
+ mProgramList.close();
+
+ mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+
+ verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemChanged(any());
+ verify(mListCallbackMocks[0], never()).onItemChanged(any());
+ verify(mOnCompleteListenerMocks[0], never()).onComplete();
+ }
+
+ @Test
public void onItemChanged_forListCallbackRegisteredWithExecutor_invokesWhenIdAdded()
throws Exception {
createRadioTuner();
@@ -410,6 +458,41 @@
}
@Test
+ public void onBackgroundScanComplete_whenProgramListReady_invokesMockedCallback()
+ throws Exception {
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+ mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+
+ mTunerCallback.onBackgroundScanComplete();
+
+ verify(mTunerCallbackMock, CALLBACK_TIMEOUT).onBackgroundScanComplete();
+ }
+
+ @Test
+ public void onBackgroundScanComplete_whenProgramListNotReady_notInvokeMockedCallback()
+ throws Exception {
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+
+ mTunerCallback.onBackgroundScanComplete();
+
+ verify(mTunerCallbackMock, after(TIMEOUT_MS).never()).onBackgroundScanComplete();
+ }
+
+ @Test
+ public void onBackgroundScanComplete_afterProgramListReady_invokesMockedCallback()
+ throws Exception {
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+
+ mTunerCallback.onBackgroundScanComplete();
+ mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+
+ verify(mTunerCallbackMock, CALLBACK_TIMEOUT).onBackgroundScanComplete();
+ }
+
+ @Test
public void unregisterListCallback_withProgramUpdated_notInvokesCallback() throws Exception {
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
@@ -418,7 +501,7 @@
mProgramList.unregisterListCallback(mListCallbackMocks[0]);
mTunerCallback.onProgramListUpdated(FM_ADD_INCOMPLETE_CHUNK);
- verify(mListCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onItemChanged(any());
+ verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemChanged(any());
}
@Test
@@ -457,7 +540,7 @@
mProgramList.removeOnCompleteListener(mOnCompleteListenerMocks[0]);
mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
- verify(mOnCompleteListenerMocks[0], CALLBACK_TIMEOUT.times(0)).onComplete();
+ verify(mOnCompleteListenerMocks[0], after(TIMEOUT_MS).never()).onComplete();
}
@Test
@@ -484,7 +567,10 @@
}
private void createRadioTuner() throws Exception {
- RadioManager radioManager = new RadioManager(mContext, mRadioServiceMock);
+ mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION;
+ when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo);
+ RadioManager radioManager = new RadioManager(mContextMock, mRadioServiceMock);
+
RadioManager.BandConfig band = new RadioManager.FmBandConfig(
new RadioManager.FmBandDescriptor(RadioManager.REGION_ITU_1, RadioManager.BAND_FM,
/* lowerLimit= */ 87500, /* upperLimit= */ 108000, /* spacing= */ 200,
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
index 79a6b0d..ce3e019 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
@@ -777,6 +777,12 @@
}
@Test
+ public void toString_forModuleProperties() {
+ assertWithMessage("Module properties string").that(AMFM_PROPERTIES.toString())
+ .contains(AM_BAND_DESCRIPTOR.toString() + ", " + FM_BAND_DESCRIPTOR.toString());
+ }
+
+ @Test
public void writeToParcel_forModulePropertiesWithNullDabFrequencyTable() {
Parcel parcel = Parcel.obtain();
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index 487086c..8b257e8 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.timeout;
@@ -51,7 +52,7 @@
private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
- private static final int CALLBACK_TIMEOUT_MS = 30_000;
+ private static final int CALLBACK_TIMEOUT_MS = 500;
private static final int AM_LOWER_LIMIT_KHZ = 150;
private static final RadioManager.BandConfig TEST_BAND_CONFIG = createBandConfig();
@@ -445,7 +446,17 @@
}
@Test
- public void getProgramInfo_beforeProgramInfoSetForTunerAdapter() {
+ public void getProgramInfo_withInvalidInput_fails() {
+ RadioManager.ProgramInfo[] programInfoArray = new RadioManager.ProgramInfo[2];
+
+ int status = mRadioTuner.getProgramInformation(programInfoArray);
+
+ assertWithMessage("Status for getting program info with input array of wrong size")
+ .that(status).isEqualTo(RadioManager.STATUS_BAD_VALUE);
+ }
+
+ @Test
+ public void getProgramInfo_beforeProgramInfoSetForTunerAdapter_fails() {
RadioManager.ProgramInfo[] programInfoArray = new RadioManager.ProgramInfo[1];
int status = mRadioTuner.getProgramInformation(programInfoArray);
@@ -732,6 +743,13 @@
}
@Test
+ public void onCurrentProgramInfoChanged_withNullInfo_notInvokeMockCallback() throws Exception {
+ mTunerCallback.onCurrentProgramInfoChanged(null);
+
+ verify(mCallbackMock, after(CALLBACK_TIMEOUT_MS).never()).onProgramInfoChanged(any());
+ }
+
+ @Test
public void onProgramListChanged_forTunerCallbackAdapter() throws Exception {
mTunerCallback.onProgramListChanged();
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index e7d7d640..7bef55e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -62,6 +62,8 @@
assertThat(clone.supportsSwitchingToNextInputMethod(), is(false));
assertThat(imi.isInlineSuggestionsEnabled(), is(false));
assertThat(imi.supportsInlineSuggestionsWithTouchExploration(), is(false));
+ assertThat(imi.supportsStylusHandwriting(), is(false));
+ assertThat(imi.createStylusHandwritingSettingsActivityIntent(), equalTo(null));
}
@Test
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
index 64df348..e82b699 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
@@ -41,34 +41,58 @@
new EqualsTester()
.addEqualityGroup(
- new HdmiPortInfo(portId, portType, address, isCec, isMhl, isArcSupported,
- isEarcSupported),
- new HdmiPortInfo(portId, portType, address, isCec, isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported),
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(
- portId + 1, portType, address, isCec, isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId + 1, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(
- portId, portType + 1, address, isCec, isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType + 1, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(
- portId, portType, address + 1, isCec, isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address + 1)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(portId, portType, address, !isCec, isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(!isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(portId, portType, address, isCec, !isMhl, isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(!isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(portId, portType, address, isCec, isMhl, !isArcSupported,
- isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(!isArcSupported)
+ .setEarcSupported(isEarcSupported))
.addEqualityGroup(
- new HdmiPortInfo(portId, portType, address, isCec, isMhl, isArcSupported,
- !isEarcSupported))
+ new HdmiPortInfo.Builder(portId, portType, address)
+ .setCecSupported(isCec)
+ .setMhlSupported(isMhl)
+ .setArcSupported(isArcSupported)
+ .setEarcSupported(!isEarcSupported))
.testEquals();
}
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index bf7f3bd..a37cb80 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -310,6 +310,7 @@
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<!-- Permission required for UiModeManager CTS test -->
<permission name="android.permission.READ_PROJECTION_STATE"/>
+ <permission name="android.permission.READ_WALLPAPER_INTERNAL"/>
<permission name="android.permission.READ_WIFI_CREDENTIAL"/>
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 3c654d6..e60506f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -26,7 +26,9 @@
import android.hardware.HardwareBuffer;
import android.os.Build;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.SharedMemory;
import android.os.StrictMode;
import android.os.Trace;
import android.util.DisplayMetrics;
@@ -38,6 +40,7 @@
import libcore.util.NativeAllocationRegistry;
+import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.nio.Buffer;
@@ -738,6 +741,26 @@
}
/**
+ * Returns the shared memory handle to the pixel storage if the bitmap is already using
+ * shared memory and null if it is not. The SharedMemory object is then useful to then pass
+ * through HIDL APIs (e.g. WearOS's DisplayOffload service).
+ *
+ * @hide
+ */
+ public SharedMemory getSharedMemory() {
+ checkRecycled("Cannot access shared memory of a recycled bitmap");
+ if (nativeIsBackedByAshmem(mNativePtr)) {
+ try {
+ int fd = nativeGetAshmemFD(mNativePtr);
+ return SharedMemory.fromFileDescriptor(ParcelFileDescriptor.fromFd(fd));
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to create dup'd file descriptor for shared bitmap memory");
+ }
+ }
+ return null;
+ }
+
+ /**
* Create a hardware bitmap backed by a {@link HardwareBuffer}.
*
* <p>The passed HardwareBuffer's usage flags must contain
@@ -2294,6 +2317,7 @@
boolean isMutable);
private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
+ private static native int nativeGetAshmemFD(long nativeBitmap);
private static native long nativeGetNativeFinalizer();
private static native void nativeRecycle(long nativeBitmap);
@UnsupportedAppUsage
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 89d6304..f815a5e 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -992,6 +992,15 @@
}
/**
+ * Notifies the hardware renderer about upcoming expensive frames.
+ *
+ * @hide
+ */
+ public void notifyExpensiveFrame() {
+ nNotifyExpensiveFrame(mNativeProxy);
+ }
+
+ /**
* b/68769804, b/66945974: For low FPS experiments.
*
* @hide
@@ -1553,4 +1562,6 @@
private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled);
private static native void nNotifyCallbackPending(long nativeProxy);
+
+ private static native void nNotifyExpensiveFrame(long nativeProxy);
}
diff --git a/graphics/java/android/graphics/drawable/LottieDrawable.java b/graphics/java/android/graphics/drawable/LottieDrawable.java
deleted file mode 100644
index c1f1b50..0000000
--- a/graphics/java/android/graphics/drawable/LottieDrawable.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.drawable;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-
-import dalvik.annotation.optimization.FastNative;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.io.IOException;
-
-/**
- * {@link Drawable} for drawing Lottie files.
- *
- * <p>The framework handles decoding subsequent frames in another thread and
- * updating when necessary. The drawable will only animate while it is being
- * displayed.</p>
- *
- * @hide
- */
-@SuppressLint("NotCloseable")
-public class LottieDrawable extends Drawable implements Animatable {
- private long mNativePtr;
-
- /**
- * Create an animation from the provided JSON string
- * @hide
- */
- private LottieDrawable(@NonNull String animationJson) throws IOException {
- mNativePtr = nCreate(animationJson);
- if (mNativePtr == 0) {
- throw new IOException("could not make LottieDrawable from json");
- }
-
- final long nativeSize = nNativeByteSize(mNativePtr);
- NativeAllocationRegistry registry = new NativeAllocationRegistry(
- LottieDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
- registry.registerNativeAllocation(this, mNativePtr);
- }
-
- /**
- * Factory for LottieDrawable, throws IOException if native Skottie Builder fails to parse
- */
- public static LottieDrawable makeLottieDrawable(@NonNull String animationJson)
- throws IOException {
- return new LottieDrawable(animationJson);
- }
-
-
-
- /**
- * Draw the current frame to the Canvas.
- * @hide
- */
- @Override
- public void draw(@NonNull Canvas canvas) {
- if (mNativePtr == 0) {
- throw new IllegalStateException("called draw on empty LottieDrawable");
- }
-
- nDraw(mNativePtr, canvas.getNativeCanvasWrapper());
- }
-
- /**
- * Start the animation. Needs to be called before draw calls.
- * @hide
- */
- @Override
- public void start() {
- if (mNativePtr == 0) {
- throw new IllegalStateException("called start on empty LottieDrawable");
- }
-
- if (nStart(mNativePtr)) {
- invalidateSelf();
- }
- }
-
- /**
- * Stops the animation playback. Does not release anything.
- * @hide
- */
- @Override
- public void stop() {
- if (mNativePtr == 0) {
- throw new IllegalStateException("called stop on empty LottieDrawable");
- }
- nStop(mNativePtr);
- }
-
- /**
- * Return whether the animation is currently running.
- */
- @Override
- public boolean isRunning() {
- if (mNativePtr == 0) {
- throw new IllegalStateException("called isRunning on empty LottieDrawable");
- }
- return nIsRunning(mNativePtr);
- }
-
- @Override
- public int getOpacity() {
- // We assume translucency to avoid checking each pixel.
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- //TODO
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- //TODO
- }
-
- private static native long nCreate(String json);
- private static native void nDraw(long nativeInstance, long nativeCanvas);
- @FastNative
- private static native long nGetNativeFinalizer();
- @FastNative
- private static native long nNativeByteSize(long nativeInstance);
- @FastNative
- private static native boolean nIsRunning(long nativeInstance);
- @FastNative
- private static native boolean nStart(long nativeInstance);
- @FastNative
- private static native boolean nStop(long nativeInstance);
-
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index b13c672..57ba6bb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -99,7 +99,7 @@
ActivityEmbeddingComponent {
static final String TAG = "SplitController";
static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
@VisibleForTesting
@GuardedBy("mLock")
diff --git a/libs/WindowManager/Shell/res/color/letterbox_restart_button_background_ripple.xml b/libs/WindowManager/Shell/res/color/letterbox_restart_button_background_ripple.xml
new file mode 100644
index 0000000..a3ca74f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/letterbox_restart_button_background_ripple.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_900" android:alpha="0.6" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/letterbox_restart_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/color/letterbox_restart_dismiss_button_background_ripple.xml
new file mode 100644
index 0000000..a3ca74f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/letterbox_restart_dismiss_button_background_ripple.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_900" android:alpha="0.6" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml
new file mode 100644
index 0000000..60f3cfe
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+ <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/>
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml
new file mode 100644
index 0000000..ef97ea1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/letterbox_restart_button_background_ripple">
+ <item android:drawable="@drawable/letterbox_restart_button_background"/>
+</ripple>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_button.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_button.xml
new file mode 100644
index 0000000..c247c6e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_button.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_checked="true"
+ android:drawable="@drawable/letterbox_restart_checkbox_checked" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/letterbox_restart_checkbox_checked" />
+ <item android:state_pressed="false"
+ android:drawable="@drawable/letterbox_restart_checkbox_unchecked" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_checked.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_checked.xml
new file mode 100644
index 0000000..4f97e2c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_checked.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20"
+ android:tint="?android:attr/textColorSecondary">
+ <group
+ android:scaleX="0.83333333333"
+ android:scaleY="0.83333333333"
+ android:translateX="0"
+ android:translateY="0">
+ <path
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M10.6,16.2 L17.65,9.15 16.25,7.75 10.6,13.4 7.75,10.55 6.35,11.95ZM5,21Q4.175,21 3.587,20.413Q3,19.825 3,19V5Q3,4.175 3.587,3.587Q4.175,3 5,3H19Q19.825,3 20.413,3.587Q21,4.175 21,5V19Q21,19.825 20.413,20.413Q19.825,21 19,21Z"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_unchecked.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_unchecked.xml
new file mode 100644
index 0000000..bb14d19
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_checkbox_unchecked.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20"
+ android:tint="?android:attr/textColorSecondary">
+ <group
+ android:scaleX="0.83333333333"
+ android:scaleY="0.83333333333"
+ android:translateX="0"
+ android:translateY="0">
+ <path
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M5,21Q4.175,21 3.587,20.413Q3,19.825 3,19V5Q3,4.175 3.587,3.587Q4.175,3 5,3H19Q19.825,3 20.413,3.587Q21,4.175 21,5V19Q21,19.825 20.413,20.413Q19.825,21 19,21ZM5,19H19Q19,19 19,19Q19,19 19,19V5Q19,5 19,5Q19,5 19,5H5Q5,5 5,5Q5,5 5,5V19Q5,19 5,19Q5,19 5,19Z"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml
new file mode 100644
index 0000000..e3c18a2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <corners android:radius="@dimen/letterbox_restart_dialog_corner_radius"/>
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml
new file mode 100644
index 0000000..af89d41
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant" android:width="1dp"/>
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/>
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml
new file mode 100644
index 0000000..e32aefc
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/letterbox_restart_dismiss_button_background_ripple">
+ <item android:drawable="@drawable/letterbox_restart_dismiss_button_background"/>
+</ripple>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml
new file mode 100644
index 0000000..5053971
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:width="@dimen/letterbox_restart_dialog_title_icon_width"
+ android:height="@dimen/letterbox_restart_dialog_title_icon_height"
+ android:viewportWidth="45"
+ android:viewportHeight="44">
+ <group
+ android:scaleX="0.8"
+ android:scaleY="0.8"
+ android:translateX="8"
+ android:translateY="8">
+ <path
+ android:pathData="M0,36V24.5H3V30.85L10.4,23.45L12.55,25.6L5.15,33H11.5V36H0ZM24.5,36V33H30.85L23.5,25.65L25.65,23.5L33,30.85V24.5H36V36H24.5ZM10.35,12.5L3,5.15V11.5H0V0H11.5V3H5.15L12.5,10.35L10.35,12.5ZM25.65,12.5L23.5,10.35L30.85,3H24.5V0H36V11.5H33V5.15L25.65,12.5Z"
+ android:fillColor="?androidprv:attr/colorAccentPrimaryVariant"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_ic_arrows.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_ic_arrows.xml
new file mode 100644
index 0000000..b6e0172
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_ic_arrows.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/letterbox_restart_dialog_title_icon_width"
+ android:height="@dimen/letterbox_restart_dialog_title_icon_height"
+ android:viewportWidth="45"
+ android:viewportHeight="44">
+ <group
+ android:scaleX="0.8"
+ android:scaleY="0.8"
+ android:translateX="8"
+ android:translateY="8">
+ <path
+ android:pathData="M0,36V24.5H3V30.85L10.4,23.45L12.55,25.6L5.15,33H11.5V36H0ZM24.5,36V33H30.85L23.5,25.65L25.65,23.5L33,30.85V24.5H36V36H24.5ZM10.35,12.5L3,5.15V11.5H0V0H11.5V3H5.15L12.5,10.35L10.35,12.5ZM25.65,12.5L23.5,10.35L30.85,3H24.5V0H36V11.5H33V5.15L25.65,12.5Z"
+ android:fillColor="@color/compat_controls_text"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
new file mode 100644
index 0000000..ba9852c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
@@ -0,0 +1,142 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.wm.shell.compatui.RestartDialogLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/system_neutral1_900">
+
+ <!-- The background of the top-level layout acts as the background dim. -->
+
+ <!--TODO (b/266288912): Resolve overdraw warning -->
+
+ <!-- Vertical margin will be set dynamically since it depends on task bounds.
+ Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
+ enter animation starts. -->
+ <FrameLayout
+ android:id="@+id/letterbox_restart_dialog_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/letterbox_restart_dialog_margin"
+ android:background="@drawable/letterbox_restart_dialog_background"
+ android:alpha="0"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintWidth_max="@dimen/letterbox_restart_dialog_width">
+
+ <!-- The ScrollView should only wrap the content of the dialog, otherwise the background
+ corner radius will be cut off when scrolling to the top/bottom. -->
+
+ <ScrollView android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:padding="24dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:importantForAccessibility="no"
+ android:layout_width="@dimen/letterbox_restart_dialog_title_icon_width"
+ android:layout_height="@dimen/letterbox_restart_dialog_title_icon_height"
+ android:src="@drawable/letterbox_restart_header_ic_arrows"/>
+
+ <TextView
+ android:layout_marginVertical="16dp"
+ android:id="@+id/letterbox_restart_dialog_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/letterbox_restart_dialog_title"
+ android:textAlignment="center"
+ android:textAppearance="@style/RestartDialogTitleText"/>
+
+ <TextView
+ android:textAppearance="@style/RestartDialogBodyText"
+ android:id="@+id/letterbox_restart_dialog_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/letterbox_restart_dialog_description"
+ android:textAlignment="center"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical"
+ android:layout_marginVertical="32dp">
+
+ <CheckBox
+ android:id="@+id/letterbox_restart_dialog_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:button="@drawable/letterbox_restart_checkbox_button"/>
+
+ <TextView
+ android:textAppearance="@style/RestartDialogCheckboxText"
+ android:layout_marginStart="12dp"
+ android:id="@+id/letterbox_restart_dialog_checkbox_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/letterbox_restart_dialog_checkbox_title"
+ android:textAlignment="textStart"/>
+
+ </LinearLayout>
+
+ <FrameLayout
+ android:minHeight="@dimen/letterbox_restart_dialog_button_height"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:textAppearance="@style/RestartDialogDismissButton"
+ android:id="@+id/letterbox_restart_dialog_dismiss_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="@dimen/letterbox_restart_dialog_button_width"
+ android:minHeight="@dimen/letterbox_restart_dialog_button_height"
+ android:layout_gravity="start"
+ android:background=
+ "@drawable/letterbox_restart_dismiss_button_background_ripple"
+ android:text="@string/letterbox_restart_cancel"
+ android:contentDescription="@string/letterbox_restart_cancel"/>
+
+ <Button
+ android:textAppearance="@style/RestartDialogConfirmButton"
+ android:id="@+id/letterbox_restart_dialog_restart_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="@dimen/letterbox_restart_dialog_button_width"
+ android:minHeight="@dimen/letterbox_restart_dialog_button_height"
+ android:layout_gravity="end"
+ android:background=
+ "@drawable/letterbox_restart_button_background_ripple"
+ android:text="@string/letterbox_restart_restart"
+ android:contentDescription="@string/letterbox_restart_restart"/>
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </ScrollView>
+
+ </FrameLayout>
+
+</com.android.wm.shell.compatui.RestartDialogLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 57a8977..6919a8e 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -53,7 +53,7 @@
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бир кол режимин баштоо"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Бир кол режиминен чыгуу"</string>
- <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер параметрлери"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Кошумча меню"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Кайра топтомго кошуу"</string>
<string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -62,7 +62,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Жогорку оң жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Төмөнкү сол жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Төмөнкү оң жакка жылдыруу"</string>
- <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> жөндөөлөрү"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> параметрлери"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Калкып чыкма билдирмени жабуу"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 3ee20ea..a1da649 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -273,6 +273,39 @@
<!-- The space between two actions in the letterbox education dialog -->
<dimen name="letterbox_education_dialog_space_between_actions">24dp</dimen>
+ <!-- The margin between the dialog container and its parent. -->
+ <dimen name="letterbox_restart_dialog_margin">24dp</dimen>
+
+ <!-- The corner radius of the restart confirmation dialog. -->
+ <dimen name="letterbox_restart_dialog_corner_radius">28dp</dimen>
+
+ <!-- The fixed width of the dialog if there is enough space in the parent. -->
+ <dimen name="letterbox_restart_dialog_width">348dp</dimen>
+
+ <!-- The width of the top icon in the restart confirmation dialog. -->
+ <dimen name="letterbox_restart_dialog_title_icon_width">32dp</dimen>
+
+ <!-- The height of the top icon in the restart confirmation dialog. -->
+ <dimen name="letterbox_restart_dialog_title_icon_height">32dp</dimen>
+
+ <!-- The width of an icon in the restart confirmation dialog. -->
+ <dimen name="letterbox_restart_dialog_icon_width">40dp</dimen>
+
+ <!-- The height of an icon in the restart confirmation dialog. -->
+ <dimen name="letterbox_restart_dialog_icon_height">32dp</dimen>
+
+ <!-- The space between two actions in the restart confirmation dialog -->
+ <dimen name="letterbox_restart_dialog_space_between_actions">24dp</dimen>
+
+ <!-- The width of the buttons in the restart dialog -->
+ <dimen name="letterbox_restart_dialog_button_width">82dp</dimen>
+
+ <!-- The width of the buttons in the restart dialog -->
+ <dimen name="letterbox_restart_dialog_button_height">36dp</dimen>
+
+ <!-- The corner radius of the buttons in the restart dialog -->
+ <dimen name="letterbox_restart_dialog_button_radius">18dp</dimen>
+
<!-- The width of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_width">200dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 9490ddc..3fd97ef 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -193,6 +193,23 @@
<!-- Accessibility description of the letterbox education toast expand to dialog button. [CHAR LIMIT=NONE] -->
<string name="letterbox_education_expand_button_description">Expand for more information.</string>
+ <!-- The title of the restart confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="letterbox_restart_dialog_title">Restart for a better view?</string>
+
+ <!-- The description of the restart confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="letterbox_restart_dialog_description">You can restart the app so it looks better on
+ your screen, but you may lose your progress or any unsaved changes
+ </string>
+
+ <!-- Button text for dismissing the restart confirmation dialog. [CHAR LIMIT=20] -->
+ <string name="letterbox_restart_cancel">Cancel</string>
+
+ <!-- Button text for dismissing the restart confirmation dialog. [CHAR LIMIT=20] -->
+ <string name="letterbox_restart_restart">Restart</string>
+
+ <!-- Checkbox text for asking to not show the restart confirmation dialog again. [CHAR LIMIT=NONE] -->
+ <string name="letterbox_restart_dialog_checkbox_title">Don\u2019t show again</string>
+
<!-- Freeform window caption strings -->
<!-- Accessibility text for the maximize window button [CHAR LIMIT=NONE] -->
<string name="maximize_button_text">Maximize</string>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index a859721..e8f340c 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -63,4 +63,42 @@
<item name="android:lineHeight">16sp</item>
<item name="android:textColor">@color/tv_pip_edu_text</item>
</style>
+
+ <style name="RestartDialogTitleText">
+ <item name="android:textSize">24sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:lineSpacingExtra">2sp</item>
+ <item name="android:textAppearance">
+ @*android:style/TextAppearance.DeviceDefault.Headline
+ </item>
+ </style>
+
+ <style name="RestartDialogBodyText">
+ <item name="android:textSize">14sp</item>
+ <item name="android:letterSpacing">0.02</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:lineSpacingExtra">2sp</item>
+ <item name="android:textAppearance">
+ @*android:style/TextAppearance.DeviceDefault.Body2
+ </item>
+ </style>
+
+ <style name="RestartDialogCheckboxText">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:lineSpacingExtra">4sp</item>
+ <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault</item>
+ </style>
+
+ <style name="RestartDialogDismissButton">
+ <item name="android:lineSpacingExtra">2sp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="RestartDialogConfirmButton">
+ <item name="android:lineSpacingExtra">2sp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ </style>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 09dc68a..2534498 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -21,6 +21,7 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.DimenRes;
+import android.annotation.Hide;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -180,7 +181,7 @@
@VisibleForTesting(visibility = PRIVATE)
public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
- int taskId, @Nullable final String locus, Executor mainExecutor,
+ int taskId, @Nullable final String locus, boolean isClearable, Executor mainExecutor,
final Bubbles.BubbleMetadataFlagListener listener) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
@@ -189,6 +190,7 @@
mKey = key;
mGroupKey = null;
mLocusId = locus != null ? new LocusId(locus) : null;
+ mIsClearable = isClearable;
mFlags = 0;
mUser = shortcutInfo.getUserHandle();
mPackageName = shortcutInfo.getPackage();
@@ -245,6 +247,11 @@
return mKey;
}
+ @Hide
+ public boolean isClearable() {
+ return mIsClearable;
+ }
+
/**
* @see StatusBarNotification#getGroupKey()
* @return the group key for this bubble, if one exists.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 3a59614..e3aefa5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -109,7 +109,8 @@
b.rawDesiredHeightResId,
b.title,
b.taskId,
- b.locusId?.id
+ b.locusId?.id,
+ b.isClearable
)
}
}
@@ -205,6 +206,7 @@
entity.title,
entity.taskId,
entity.locus,
+ entity.isClearable,
mainExecutor,
bubbleMetadataFlagListener
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
index 186b9b1..f3abc27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
@@ -27,5 +27,6 @@
@DimenRes val desiredHeightResId: Int,
val title: String? = null,
val taskId: Int,
- val locus: String? = null
+ val locus: String? = null,
+ val isClearable: Boolean = false
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index f4fa183..14c053c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -44,6 +44,9 @@
private const val ATTR_TASK_ID = "tid"
private const val ATTR_LOCUS = "l"
+// TODO rename it to dismissable to follow NotificationEntry namings
+private const val ATTR_CLEARABLE = "d"
+
/**
* Writes the bubbles in xml format into given output stream.
*/
@@ -84,6 +87,7 @@
bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) }
serializer.attribute(null, ATTR_TASK_ID, bubble.taskId.toString())
bubble.locus?.let { serializer.attribute(null, ATTR_LOCUS, it) }
+ serializer.attribute(null, ATTR_CLEARABLE, bubble.isClearable.toString())
serializer.endTag(null, TAG_BUBBLE)
} catch (e: IOException) {
throw RuntimeException(e)
@@ -142,7 +146,8 @@
parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null,
parser.getAttributeWithName(ATTR_TITLE),
parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID,
- parser.getAttributeWithName(ATTR_LOCUS)
+ parser.getAttributeWithName(ATTR_LOCUS),
+ parser.getAttributeWithName(ATTR_CLEARABLE)?.toBoolean() ?: false
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
index 4f33a71..06f0a70 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
@@ -16,11 +16,12 @@
package com.android.wm.shell.compatui;
+import android.annotation.NonNull;
+import android.app.TaskInfo;
import android.content.Context;
+import android.content.SharedPreferences;
import android.provider.DeviceConfig;
-import androidx.annotation.NonNull;
-
import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ShellMainThread;
@@ -34,11 +35,27 @@
@WMSingleton
public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedListener {
- static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog";
+ private static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG =
+ "enable_letterbox_restart_confirmation_dialog";
- static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION =
+ private static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION =
"enable_letterbox_reachability_education";
+ private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG = true;
+
+ private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = false;
+
+ /**
+ * The name of the {@link SharedPreferences} that holds which user has seen the Restart
+ * confirmation dialog.
+ */
+ private static final String DONT_SHOW_RESTART_DIALOG_PREF_NAME = "dont_show_restart_dialog";
+
+ /**
+ * The {@link SharedPreferences} instance for {@link #DONT_SHOW_RESTART_DIALOG_PREF_NAME}.
+ */
+ private final SharedPreferences mSharedPreferences;
+
// Whether the extended restart dialog is enabled
private boolean mIsRestartDialogEnabled;
@@ -64,12 +81,15 @@
mIsReachabilityEducationEnabled = context.getResources().getBoolean(
R.bool.config_letterboxIsReachabilityEducationEnabled);
mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG, false);
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG,
+ DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG);
mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION,
- false);
+ DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor,
this);
+ mSharedPreferences = context.getSharedPreferences(DONT_SHOW_RESTART_DIALOG_PREF_NAME,
+ Context.MODE_PRIVATE);
}
/**
@@ -102,18 +122,37 @@
mIsReachabilityEducationOverrideEnabled = enabled;
}
+ boolean getDontShowRestartDialogAgain(TaskInfo taskInfo) {
+ final int userId = taskInfo.userId;
+ final String packageName = taskInfo.topActivity.getPackageName();
+ return mSharedPreferences.getBoolean(
+ getDontShowAgainRestartKey(userId, packageName), /* default= */ false);
+ }
+
+ void setDontShowRestartDialogAgain(TaskInfo taskInfo) {
+ final int userId = taskInfo.userId;
+ final String packageName = taskInfo.topActivity.getPackageName();
+ mSharedPreferences.edit().putBoolean(getDontShowAgainRestartKey(userId, packageName),
+ true).apply();
+ }
+
@Override
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
- // TODO(b/263349751): Update flag and default value to true
if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_RESTART_DIALOG)) {
mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG,
- false);
+ DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG);
}
+ // TODO(b/263349751): Update flag and default value to true
if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION)) {
mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, false);
+ KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION,
+ DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION);
}
}
-}
+
+ private String getDontShowAgainRestartKey(int userId, String packageName) {
+ return packageName + "@" + userId;
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 6627de5..3b2db51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -24,6 +24,7 @@
import android.hardware.display.DisplayManager;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.view.Display;
import android.view.InsetsSourceControl;
@@ -49,6 +50,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
@@ -91,6 +93,18 @@
private final SparseArray<CompatUIWindowManager> mActiveCompatLayouts = new SparseArray<>(0);
/**
+ * {@link SparseArray} that maps task ids to {@link RestartDialogWindowManager} that are
+ * currently visible
+ */
+ private final SparseArray<RestartDialogWindowManager> mTaskIdToRestartDialogWindowManagerMap =
+ new SparseArray<>(0);
+
+ /**
+ * {@link Set} of task ids for which we need to display a restart confirmation dialog
+ */
+ private Set<Integer> mSetOfTaskIdsShowingRestartDialog = new HashSet<>();
+
+ /**
* The active Letterbox Education layout if there is one (there can be at most one active).
*
* <p>An active layout is a layout that is eligible to be shown for the associated task but
@@ -111,12 +125,15 @@
private final ShellExecutor mMainExecutor;
private final Lazy<Transitions> mTransitionsLazy;
private final DockStateReader mDockStateReader;
+ private final CompatUIConfiguration mCompatUIConfiguration;
private CompatUICallback mCallback;
// Only show each hint once automatically in the process life.
private final CompatUIHintsState mCompatUIHintsState;
+ private final CompatUIShellCommandHandler mCompatUIShellCommandHandler;
+
// Indicates if the keyguard is currently showing, in which case compat UIs shouldn't
// be shown.
private boolean mKeyguardShowing;
@@ -130,7 +147,9 @@
SyncTransactionQueue syncQueue,
ShellExecutor mainExecutor,
Lazy<Transitions> transitionsLazy,
- DockStateReader dockStateReader) {
+ DockStateReader dockStateReader,
+ CompatUIConfiguration compatUIConfiguration,
+ CompatUIShellCommandHandler compatUIShellCommandHandler) {
mContext = context;
mShellController = shellController;
mDisplayController = displayController;
@@ -140,14 +159,17 @@
mMainExecutor = mainExecutor;
mTransitionsLazy = transitionsLazy;
mCompatUIHintsState = new CompatUIHintsState();
- shellInit.addInitCallback(this::onInit, this);
mDockStateReader = dockStateReader;
+ mCompatUIConfiguration = compatUIConfiguration;
+ mCompatUIShellCommandHandler = compatUIShellCommandHandler;
+ shellInit.addInitCallback(this::onInit, this);
}
private void onInit() {
mShellController.addKeyguardChangeListener(this);
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
+ mCompatUIShellCommandHandler.onInit();
}
/** Sets the callback for UI interactions. */
@@ -164,6 +186,9 @@
*/
public void onCompatInfoChanged(TaskInfo taskInfo,
@Nullable ShellTaskOrganizer.TaskListener taskListener) {
+ if (taskInfo != null && !taskInfo.topActivityInSizeCompat) {
+ mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
+ }
if (taskInfo.configuration == null || taskListener == null) {
// Null token means the current foreground activity is not in compatibility mode.
removeLayouts(taskInfo.taskId);
@@ -172,6 +197,7 @@
createOrUpdateCompatLayout(taskInfo, taskListener);
createOrUpdateLetterboxEduLayout(taskInfo, taskListener);
+ createOrUpdateRestartDialogLayout(taskInfo, taskListener);
}
@Override
@@ -278,7 +304,21 @@
ShellTaskOrganizer.TaskListener taskListener) {
return new CompatUIWindowManager(context,
taskInfo, mSyncQueue, mCallback, taskListener,
- mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState);
+ mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState,
+ mCompatUIConfiguration, this::onRestartButtonClicked);
+ }
+
+ private void onRestartButtonClicked(
+ Pair<TaskInfo, ShellTaskOrganizer.TaskListener> taskInfoState) {
+ if (mCompatUIConfiguration.isRestartDialogEnabled()
+ && !mCompatUIConfiguration.getDontShowRestartDialogAgain(
+ taskInfoState.first)) {
+ // We need to show the dialog
+ mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId);
+ onCompatInfoChanged(taskInfoState.first, taskInfoState.second);
+ } else {
+ mCallback.onSizeCompatRestartButtonClicked(taskInfoState.first.taskId);
+ }
}
private void createOrUpdateLetterboxEduLayout(TaskInfo taskInfo,
@@ -327,6 +367,60 @@
mActiveLetterboxEduLayout = null;
}
+ private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo,
+ ShellTaskOrganizer.TaskListener taskListener) {
+ RestartDialogWindowManager layout =
+ mTaskIdToRestartDialogWindowManagerMap.get(taskInfo.taskId);
+ if (layout != null) {
+ // TODO(b/266262111) Handle theme change when taskListener changes
+ if (layout.getTaskListener() != taskListener) {
+ mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
+ }
+ layout.setRequestRestartDialog(
+ mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId));
+ // UI already exists, update the UI layout.
+ if (!layout.updateCompatInfo(taskInfo, taskListener,
+ showOnDisplay(layout.getDisplayId()))) {
+ // The layout is no longer eligible to be shown, remove from active layouts.
+ mTaskIdToRestartDialogWindowManagerMap.remove(taskInfo.taskId);
+ }
+ return;
+ }
+ // Create a new UI layout.
+ final Context context = getOrCreateDisplayContext(taskInfo.displayId);
+ if (context == null) {
+ return;
+ }
+ layout = createRestartDialogWindowManager(context, taskInfo, taskListener);
+ layout.setRequestRestartDialog(
+ mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId));
+ if (layout.createLayout(showOnDisplay(taskInfo.displayId))) {
+ // The new layout is eligible to be shown, add it the active layouts.
+ mTaskIdToRestartDialogWindowManagerMap.put(taskInfo.taskId, layout);
+ }
+ }
+
+ @VisibleForTesting
+ RestartDialogWindowManager createRestartDialogWindowManager(Context context, TaskInfo taskInfo,
+ ShellTaskOrganizer.TaskListener taskListener) {
+ return new RestartDialogWindowManager(context, taskInfo, mSyncQueue, taskListener,
+ mDisplayController.getDisplayLayout(taskInfo.displayId), mTransitionsLazy.get(),
+ this::onRestartDialogCallback, this::onRestartDialogDismissCallback,
+ mCompatUIConfiguration);
+ }
+
+ private void onRestartDialogCallback(
+ Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) {
+ mTaskIdToRestartDialogWindowManagerMap.remove(stateInfo.first.taskId);
+ mCallback.onSizeCompatRestartButtonClicked(stateInfo.first.taskId);
+ }
+
+ private void onRestartDialogDismissCallback(
+ Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) {
+ mSetOfTaskIdsShowingRestartDialog.remove(stateInfo.first.taskId);
+ onCompatInfoChanged(stateInfo.first, stateInfo.second);
+ }
+
private void removeLayouts(int taskId) {
final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId);
if (layout != null) {
@@ -338,6 +432,14 @@
mActiveLetterboxEduLayout.release();
mActiveLetterboxEduLayout = null;
}
+
+ final RestartDialogWindowManager restartLayout =
+ mTaskIdToRestartDialogWindowManagerMap.get(taskId);
+ if (restartLayout != null) {
+ restartLayout.release();
+ mTaskIdToRestartDialogWindowManagerMap.remove(taskId);
+ mSetOfTaskIdsShowingRestartDialog.remove(taskId);
+ }
}
private Context getOrCreateDisplayContext(int displayId) {
@@ -382,6 +484,14 @@
if (mActiveLetterboxEduLayout != null && condition.test(mActiveLetterboxEduLayout)) {
callback.accept(mActiveLetterboxEduLayout);
}
+ for (int i = 0; i < mTaskIdToRestartDialogWindowManagerMap.size(); i++) {
+ final int taskId = mTaskIdToRestartDialogWindowManagerMap.keyAt(i);
+ final RestartDialogWindowManager layout =
+ mTaskIdToRestartDialogWindowManagerMap.get(taskId);
+ if (layout != null && condition.test(layout)) {
+ callback.accept(layout);
+ }
+ }
}
/** An implementation of {@link OnInsetsChangedListener} for a given display id. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index bce3ec4..c14704d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -21,12 +21,14 @@
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.app.TaskInfo.CameraCompatControlState;
import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
@@ -38,6 +40,8 @@
import com.android.wm.shell.compatui.CompatUIController.CompatUICallback;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import java.util.function.Consumer;
+
/**
* Window manager for the Size Compat restart button and Camera Compat control.
*/
@@ -50,6 +54,13 @@
private final CompatUICallback mCallback;
+ private final CompatUIConfiguration mCompatUIConfiguration;
+
+ private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked;
+
+ @NonNull
+ private TaskInfo mTaskInfo;
+
// Remember the last reported states in case visibility changes due to keyguard or IME updates.
@VisibleForTesting
boolean mHasSizeCompat;
@@ -68,12 +79,16 @@
CompatUIWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, CompatUICallback callback,
ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
- CompatUIHintsState compatUIHintsState) {
+ CompatUIHintsState compatUIHintsState, CompatUIConfiguration compatUIConfiguration,
+ Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mTaskInfo = taskInfo;
mCallback = callback;
mHasSizeCompat = taskInfo.topActivityInSizeCompat;
mCameraCompatControlState = taskInfo.cameraCompatControlState;
mCompatUIHintsState = compatUIHintsState;
+ mCompatUIConfiguration = compatUIConfiguration;
+ mOnRestartButtonClicked = onRestartButtonClicked;
}
@Override
@@ -119,6 +134,7 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
+ mTaskInfo = taskInfo;
final boolean prevHasSizeCompat = mHasSizeCompat;
final int prevCameraCompatControlState = mCameraCompatControlState;
mHasSizeCompat = taskInfo.topActivityInSizeCompat;
@@ -138,7 +154,7 @@
/** Called when the restart button is clicked. */
void onRestartButtonClicked() {
- mCallback.onSizeCompatRestartButtonClicked(mTaskId);
+ mOnRestartButtonClicked.accept(Pair.create(mTaskInfo, getTaskListener()));
}
/** Called when the camera treatment button is clicked. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index 2cc9f45..34e650a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -151,6 +151,7 @@
@Override
public void setConfiguration(Configuration configuration) {
super.setConfiguration(configuration);
+ // TODO(b/266262111): Investigate loss of theme configuration when switching TaskListener
mContext = mContext.createConfigurationContext(configuration);
}
@@ -168,6 +169,10 @@
return mLeash;
}
+ protected ShellTaskOrganizer.TaskListener getTaskListener() {
+ return mTaskListener;
+ }
+
/** Inits the z-order of the surface. */
private void initSurface(SurfaceControl leash) {
final int z = getZOrder();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java
new file mode 100644
index 0000000..c53e638
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.wm.shell.R;
+
+import java.util.function.Consumer;
+
+/**
+ * Container for a SCM restart confirmation dialog and background dim.
+ */
+public class RestartDialogLayout extends ConstraintLayout implements DialogContainerSupplier {
+
+ private View mDialogContainer;
+ private TextView mDialogTitle;
+ private Drawable mBackgroundDim;
+
+ public RestartDialogLayout(Context context) {
+ this(context, null);
+ }
+
+ public RestartDialogLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public View getDialogContainerView() {
+ return mDialogContainer;
+ }
+
+ TextView getDialogTitle() {
+ return mDialogTitle;
+ }
+
+ @Override
+ public Drawable getBackgroundDimDrawable() {
+ return mBackgroundDim;
+ }
+
+ /**
+ * Register a callback for the dismiss button and background dim.
+ *
+ * @param callback The callback to register or null if all on click listeners should be removed.
+ */
+ void setDismissOnClickListener(@Nullable Runnable callback) {
+ final OnClickListener listener = callback == null ? null : view -> callback.run();
+ findViewById(R.id.letterbox_restart_dialog_dismiss_button).setOnClickListener(listener);
+ }
+
+ /**
+ * Register a callback for the restart button
+ *
+ * @param callback The callback to register or null if all on click listeners should be removed.
+ */
+ void setRestartOnClickListener(@Nullable Consumer<Boolean> callback) {
+ final CheckBox dontShowAgainCheckbox = findViewById(R.id.letterbox_restart_dialog_checkbox);
+ final OnClickListener listener = callback == null ? null : view -> callback.accept(
+ dontShowAgainCheckbox.isChecked());
+ findViewById(R.id.letterbox_restart_dialog_restart_button).setOnClickListener(listener);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDialogContainer = findViewById(R.id.letterbox_restart_dialog_container);
+ mDialogTitle = findViewById(R.id.letterbox_restart_dialog_title);
+ mBackgroundDim = getBackground().mutate();
+ // Set the alpha of the background dim to 0 for enter animation.
+ mBackgroundDim.setAlpha(0);
+ // We add a no-op on-click listener to the dialog container so that clicks on it won't
+ // propagate to the listener of the layout (which represents the background dim).
+ mDialogContainer.setOnClickListener(view -> {});
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
new file mode 100644
index 0000000..10f25d0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.graphics.Rect;
+import android.provider.Settings;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
+
+import java.util.function.Consumer;
+
+/**
+ * Window manager for the Restart Dialog.
+ *
+ * TODO(b/263484314): Create abstraction of RestartDialogWindowManager and LetterboxEduWindowManager
+ */
+class RestartDialogWindowManager extends CompatUIWindowManagerAbstract {
+
+ /**
+ * The restart dialog should be the topmost child of the Task in case there can be more
+ * than one child.
+ */
+ private static final int Z_ORDER = Integer.MAX_VALUE;
+
+ private final DialogAnimationController<RestartDialogLayout> mAnimationController;
+
+ private final Transitions mTransitions;
+
+ // Remember the last reported state in case visibility changes due to keyguard or IME updates.
+ private boolean mRequestRestartDialog;
+
+ private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback;
+
+ private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartCallback;
+
+ private final CompatUIConfiguration mCompatUIConfiguration;
+
+ /**
+ * The vertical margin between the dialog container and the task stable bounds (excluding
+ * insets).
+ */
+ private final int mDialogVerticalMargin;
+
+ @NonNull
+ private TaskInfo mTaskInfo;
+
+ @Nullable
+ @VisibleForTesting
+ RestartDialogLayout mLayout;
+
+ RestartDialogWindowManager(Context context, TaskInfo taskInfo,
+ SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
+ DisplayLayout displayLayout, Transitions transitions,
+ Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartCallback,
+ Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback,
+ CompatUIConfiguration compatUIConfiguration) {
+ this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
+ onRestartCallback, onDismissCallback,
+ new DialogAnimationController<>(context, "RestartDialogWindowManager"),
+ compatUIConfiguration);
+ }
+
+ @VisibleForTesting
+ RestartDialogWindowManager(Context context, TaskInfo taskInfo,
+ SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
+ DisplayLayout displayLayout, Transitions transitions,
+ Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartCallback,
+ Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback,
+ DialogAnimationController<RestartDialogLayout> animationController,
+ CompatUIConfiguration compatUIConfiguration) {
+ super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mTaskInfo = taskInfo;
+ mTransitions = transitions;
+ mOnDismissCallback = onDismissCallback;
+ mOnRestartCallback = onRestartCallback;
+ mAnimationController = animationController;
+ mDialogVerticalMargin = (int) mContext.getResources().getDimension(
+ R.dimen.letterbox_restart_dialog_margin);
+ mCompatUIConfiguration = compatUIConfiguration;
+ }
+
+ @Override
+ protected int getZOrder() {
+ return Z_ORDER;
+ }
+
+ @Override
+ @Nullable
+ protected View getLayout() {
+ return mLayout;
+ }
+
+ @Override
+ protected void removeLayout() {
+ mLayout = null;
+ }
+
+ @Override
+ protected boolean eligibleToShowLayout() {
+ // We don't show this dialog if the user has explicitly selected so clicking on a checkbox.
+ return mRequestRestartDialog && !isTaskbarEduShowing() && (mLayout != null
+ || !mCompatUIConfiguration.getDontShowRestartDialogAgain(mTaskInfo));
+ }
+
+ @Override
+ protected View createLayout() {
+ mLayout = inflateLayout();
+ updateDialogMargins();
+
+ // startEnterAnimation will be called immediately if shell-transitions are disabled.
+ mTransitions.runOnIdle(this::startEnterAnimation);
+
+ return mLayout;
+ }
+
+ void setRequestRestartDialog(boolean enabled) {
+ mRequestRestartDialog = enabled;
+ }
+
+ @Override
+ public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
+ boolean canShow) {
+ mTaskInfo = taskInfo;
+ return super.updateCompatInfo(taskInfo, taskListener, canShow);
+ }
+
+ private void updateDialogMargins() {
+ if (mLayout == null) {
+ return;
+ }
+ final View dialogContainer = mLayout.getDialogContainerView();
+ ViewGroup.MarginLayoutParams marginParams =
+ (ViewGroup.MarginLayoutParams) dialogContainer.getLayoutParams();
+
+ final Rect taskBounds = getTaskBounds();
+ final Rect taskStableBounds = getTaskStableBounds();
+
+ marginParams.topMargin = taskStableBounds.top - taskBounds.top + mDialogVerticalMargin;
+ marginParams.bottomMargin =
+ taskBounds.bottom - taskStableBounds.bottom + mDialogVerticalMargin;
+ dialogContainer.setLayoutParams(marginParams);
+ }
+
+ private RestartDialogLayout inflateLayout() {
+ return (RestartDialogLayout) LayoutInflater.from(mContext).inflate(
+ R.layout.letterbox_restart_dialog_layout, null);
+ }
+
+ private void startEnterAnimation() {
+ if (mLayout == null) {
+ // Dialog has already been released.
+ return;
+ }
+ mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+ this::onDialogEnterAnimationEnded);
+ }
+
+ private void onDialogEnterAnimationEnded() {
+ if (mLayout == null) {
+ // Dialog has already been released.
+ return;
+ }
+ mLayout.setDismissOnClickListener(this::onDismiss);
+ mLayout.setRestartOnClickListener(dontShowAgain -> {
+ if (mLayout != null) {
+ mLayout.setDismissOnClickListener(null);
+ mAnimationController.startExitAnimation(mLayout, () -> {
+ release();
+ });
+ }
+ if (dontShowAgain) {
+ mCompatUIConfiguration.setDontShowRestartDialogAgain(mTaskInfo);
+ }
+ mOnRestartCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
+ });
+ // Focus on the dialog title for accessibility.
+ mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
+
+ private void onDismiss() {
+ if (mLayout == null) {
+ return;
+ }
+
+ mLayout.setDismissOnClickListener(null);
+ mAnimationController.startExitAnimation(mLayout, () -> {
+ release();
+ mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
+ });
+ }
+
+ @Override
+ public void release() {
+ mAnimationController.cancelAnimation();
+ super.release();
+ }
+
+ @Override
+ protected void onParentBoundsChanged() {
+ if (mLayout == null) {
+ return;
+ }
+ // Both the layout dimensions and dialog margins depend on the parent bounds.
+ WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
+ mLayout.setLayoutParams(windowLayoutParams);
+ updateDialogMargins();
+ relayout(windowLayoutParams);
+ }
+
+ @Override
+ protected void updateSurfacePosition() {
+ // Nothing to do, since the position of the surface is fixed to the top left corner (0,0)
+ // of the task (parent surface), which is the default position of a surface.
+ }
+
+ @Override
+ protected WindowManager.LayoutParams getWindowLayoutParams() {
+ final Rect taskBounds = getTaskBounds();
+ return getWindowLayoutParams(/* width= */ taskBounds.width(), /* height= */
+ taskBounds.height());
+ }
+
+ @VisibleForTesting
+ boolean isTaskbarEduShowing() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ LAUNCHER_TASKBAR_EDUCATION_SHOWING, /* def= */ 0) == 1;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 7055aca0..eee8ad8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -57,7 +57,9 @@
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.compatui.CompatUIConfiguration;
import com.android.wm.shell.compatui.CompatUIController;
+import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
@@ -197,10 +199,11 @@
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
@ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy,
- DockStateReader dockStateReader) {
+ DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration,
+ CompatUIShellCommandHandler compatUIShellCommandHandler) {
return new CompatUIController(context, shellInit, shellController, displayController,
displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy,
- dockStateReader);
+ dockStateReader, compatUIConfiguration, compatUIShellCommandHandler);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index b9caf62..26f47fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -114,7 +114,9 @@
t.setPosition(leash, positionInParent.x, positionInParent.y);
t.setAlpha(leash, 1f);
t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
+ if (taskInfo.isVisible) {
+ t.show(leash);
+ }
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 38099fc..21eeaa2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -535,17 +536,11 @@
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
- try {
- adapter.getRunner().onAnimationCancelled(false /* isKeyguardOccluded */);
- ActivityTaskManager.getService().startActivityFromRecents(taskId, options2);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
+ taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
- return;
}
}
mStageCoordinator.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
@@ -586,17 +581,11 @@
fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
- try {
- adapter.getRunner().onAnimationCancelled(false /* isKeyguardOccluded */);
- pendingIntent1.send();
- } catch (RemoteException | PendingIntent.CanceledException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
+ pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
- return;
}
}
mStageCoordinator.startIntentsWithLegacyTransition(pendingIntent1, fillInIntent1, options1,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a6c4ac2..39cf5f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -629,9 +629,19 @@
RemoteAnimationAdapter adapter, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
+ if (pendingIntent2 == null) {
+ // Launching a solo task.
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
+ options1 = activityOptions.toBundle();
+ addActivityOptions(options1, null /* launchTarget */);
+ wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
+ mSyncQueue.queue(wct);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
-
startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, options2, splitPosition,
splitRatio, adapter, instanceId);
}
@@ -666,9 +676,19 @@
InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
+ if (taskId == INVALID_TASK_ID) {
+ // Launching a solo task.
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
+ options1 = activityOptions.toBundle();
+ addActivityOptions(options1, null /* launchTarget */);
+ wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
+ mSyncQueue.queue(wct);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
-
startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
instanceId);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index fc2a828..44d6a0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -81,7 +81,7 @@
/** Set to {@code true} to enable shell transitions. */
public static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 1636c5f..0a31338 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -21,7 +21,6 @@
import android.util.SparseArray
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.bubbles.storage.BubbleXmlHelperTest.Companion.sparseArraysEqual
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
@@ -36,7 +35,8 @@
// user, package, shortcut, notification key, height, res-height, title, taskId, locusId
private val user0Bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1, null),
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1, null,
+ true),
BubbleEntity(10, "com.example.chat", "alice and bob", "0k2", 0, 16537428, "title", 2,
null),
BubbleEntity(0, "com.example.messenger", "shortcut-2", "0k3", 120, 0, null,
@@ -44,7 +44,8 @@
)
private val user1Bubbles = listOf(
- BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3, null),
+ BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3, null,
+ true),
BubbleEntity(12, "com.example.chat", "alice and bob", "1k2", 0, 16537428, "title", 4,
null),
BubbleEntity(1, "com.example.messenger", "shortcut-2", "1k3", 120, 0, null,
@@ -76,6 +77,6 @@
assertEquals(actual.size(), 0)
repository.persistsToDisk(bubbles)
- assertTrue(sparseArraysEqual(bubbles, repository.readFromDisk()))
+ assertTrue(bubbles.contentEquals(repository.readFromDisk()))
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index 4ab9f87..c02e2d1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -34,7 +34,8 @@
class BubbleXmlHelperTest : ShellTestCase() {
private val user0Bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1),
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1,
+ isClearable = true),
BubbleEntity(10, "com.example.chat", "alice and bob", "0k2", 0, 16537428, "title", 2,
null),
BubbleEntity(0, "com.example.messenger", "shortcut-2", "0k3", 120, 0, null,
@@ -42,7 +43,8 @@
)
private val user1Bubbles = listOf(
- BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3),
+ BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3,
+ isClearable = true),
BubbleEntity(12, "com.example.chat", "alice and bob", "1k2", 0, 16537428, "title", 4,
null),
BubbleEntity(1, "com.example.messenger", "shortcut-2", "1k3", 120, 0, null,
@@ -51,28 +53,6 @@
private val bubbles = SparseArray<List<BubbleEntity>>()
- // Checks that the contents of the two sparse arrays are the same.
- companion object {
- fun sparseArraysEqual(
- one: SparseArray<List<BubbleEntity>>?,
- two: SparseArray<List<BubbleEntity>>?
- ): Boolean {
- if (one == null && two == null) return true
- if ((one == null) != (two == null)) return false
- if (one!!.size() != two!!.size()) return false
- for (i in 0 until one.size()) {
- val k1 = one.keyAt(i)
- val v1 = one.valueAt(i)
- val k2 = two.keyAt(i)
- val v2 = two.valueAt(i)
- if (k1 != k2 && v1 != v2) {
- return false
- }
- }
- return true
- }
- }
-
@Before
fun setup() {
bubbles.put(0, user0Bubbles)
@@ -83,14 +63,14 @@
fun testWriteXml() {
val expectedEntries = """
<bs uid="0">
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" d="true" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" d="false" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" d="false" />
</bs>
<bs uid="1">
-<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" />
-<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" />
-<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" d="true" />
+<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" d="false" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" d="false" />
</bs>
""".trimIndent()
ByteArrayOutputStream().use {
@@ -107,19 +87,19 @@
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs v="2">
<bs uid="0">
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" d="true" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" d="false" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" d="false" />
</bs>
<bs uid="1">
-<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" />
-<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" />
-<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" d="true" />
+<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" d="false" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" d="false" />
</bs>
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertTrue("failed parsing bubbles from xml\n$src", sparseArraysEqual(bubbles, actual))
+ assertTrue("failed parsing bubbles from xml\n$src", bubbles.contentEquals(actual))
}
// V0 -> V1 happened prior to release / during dogfood so nothing is saved
@@ -161,8 +141,7 @@
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertTrue("failed parsing bubbles from xml\n$src",
- sparseArraysEqual(expectedBubbles, actual))
+ assertTrue("failed parsing bubbles from xml\n$src", expectedBubbles.contentEquals(actual))
}
/**
@@ -187,7 +166,7 @@
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
assertTrue("failed parsing bubbles from xml\n$src",
- sparseArraysEqual(expectedBubbles, actual))
+ expectedBubbles.contentEquals(actual))
}
@Test
@@ -210,6 +189,6 @@
)
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
assertTrue("failed parsing bubbles from xml\n$src",
- sparseArraysEqual(expectedBubbles, actual))
+ expectedBubbles.contentEquals(actual))
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index d4408d7..05fd889 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -95,7 +95,10 @@
private @Mock Lazy<Transitions> mMockTransitionsLazy;
private @Mock CompatUIWindowManager mMockCompatLayout;
private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
+ private @Mock RestartDialogWindowManager mMockRestartDialogLayout;
private @Mock DockStateReader mDockStateReader;
+ private @Mock CompatUIConfiguration mCompatUIConfiguration;
+ private @Mock CompatUIShellCommandHandler mCompatUIShellCommandHandler;
@Captor
ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
@@ -113,10 +116,17 @@
doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId();
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
+
+ doReturn(DISPLAY_ID).when(mMockRestartDialogLayout).getDisplayId();
+ doReturn(TASK_ID).when(mMockRestartDialogLayout).getTaskId();
+ doReturn(true).when(mMockRestartDialogLayout).createLayout(anyBoolean());
+ doReturn(true).when(mMockRestartDialogLayout).updateCompatInfo(any(), any(), anyBoolean());
+
mShellInit = spy(new ShellInit(mMockExecutor));
mController = new CompatUIController(mContext, mShellInit, mMockShellController,
mMockDisplayController, mMockDisplayInsetsController, mMockImeController,
- mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader) {
+ mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader,
+ mCompatUIConfiguration, mCompatUIShellCommandHandler) {
@Override
CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
@@ -128,6 +138,12 @@
TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) {
return mMockLetterboxEduLayout;
}
+
+ @Override
+ RestartDialogWindowManager createRestartDialogWindowManager(Context context,
+ TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) {
+ return mMockRestartDialogLayout;
+ }
};
mShellInit.init();
spyOn(mController);
@@ -160,6 +176,8 @@
verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener));
verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
eq(mMockTaskListener));
+ verify(mController).createRestartDialogWindowManager(any(), eq(taskInfo),
+ eq(mMockTaskListener));
// Verify that the compat controls and letterbox education are updated with new size compat
// info.
@@ -168,10 +186,12 @@
CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
- verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- true);
- verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- true);
+ verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
+ verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
+ verify(mMockRestartDialogLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
// Verify that compat controls and letterbox education are removed with null task listener.
clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
@@ -181,12 +201,14 @@
verify(mMockCompatLayout).release();
verify(mMockLetterboxEduLayout).release();
+ verify(mMockRestartDialogLayout).release();
}
@Test
public void testOnCompatInfoChanged_createLayoutReturnsFalse() {
doReturn(false).when(mMockCompatLayout).createLayout(anyBoolean());
doReturn(false).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
+ doReturn(false).when(mMockRestartDialogLayout).createLayout(anyBoolean());
TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
CAMERA_COMPAT_CONTROL_HIDDEN);
@@ -195,6 +217,8 @@
verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener));
verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
eq(mMockTaskListener));
+ verify(mController).createRestartDialogWindowManager(any(), eq(taskInfo),
+ eq(mMockTaskListener));
// Verify that the layout is created again.
clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
@@ -202,15 +226,19 @@
verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
verify(mMockLetterboxEduLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
+ verify(mMockRestartDialogLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener));
verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
eq(mMockTaskListener));
+ verify(mController).createRestartDialogWindowManager(any(), eq(taskInfo),
+ eq(mMockTaskListener));
}
@Test
public void testOnCompatInfoChanged_updateCompatInfoReturnsFalse() {
doReturn(false).when(mMockCompatLayout).updateCompatInfo(any(), any(), anyBoolean());
doReturn(false).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
+ doReturn(false).when(mMockRestartDialogLayout).updateCompatInfo(any(), any(), anyBoolean());
TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
CAMERA_COMPAT_CONTROL_HIDDEN);
@@ -219,24 +247,33 @@
verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener));
verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
eq(mMockTaskListener));
+ verify(mController).createRestartDialogWindowManager(any(), eq(taskInfo),
+ eq(mMockTaskListener));
- clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
+ clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mMockRestartDialogLayout,
+ mController);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
- verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- true);
- verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- true);
+ verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
+ verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
+ verify(mMockRestartDialogLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ true);
// Verify that the layout is created again.
- clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
+ clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mMockRestartDialogLayout,
+ mController);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
verify(mMockLetterboxEduLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
+ verify(mMockRestartDialogLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener));
verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
eq(mMockTaskListener));
+ verify(mController).createRestartDialogWindowManager(any(), eq(taskInfo),
+ eq(mMockTaskListener));
}
@@ -260,6 +297,7 @@
verify(mMockCompatLayout, never()).release();
verify(mMockLetterboxEduLayout, never()).release();
+ verify(mMockRestartDialogLayout, never()).release();
verify(mMockDisplayInsetsController, never()).removeInsetsChangedListener(eq(DISPLAY_ID),
any());
@@ -268,6 +306,7 @@
verify(mMockDisplayInsetsController).removeInsetsChangedListener(eq(DISPLAY_ID), any());
verify(mMockCompatLayout).release();
verify(mMockLetterboxEduLayout).release();
+ verify(mMockRestartDialogLayout).release();
}
@Test
@@ -279,11 +318,13 @@
verify(mMockCompatLayout, never()).updateDisplayLayout(any());
verify(mMockLetterboxEduLayout, never()).updateDisplayLayout(any());
+ verify(mMockRestartDialogLayout, never()).updateDisplayLayout(any());
mController.onDisplayConfigurationChanged(DISPLAY_ID, new Configuration());
verify(mMockCompatLayout).updateDisplayLayout(mMockDisplayLayout);
verify(mMockLetterboxEduLayout).updateDisplayLayout(mMockDisplayLayout);
+ verify(mMockRestartDialogLayout).updateDisplayLayout(mMockDisplayLayout);
}
@Test
@@ -302,12 +343,14 @@
verify(mMockCompatLayout).updateDisplayLayout(mMockDisplayLayout);
verify(mMockLetterboxEduLayout).updateDisplayLayout(mMockDisplayLayout);
+ verify(mMockRestartDialogLayout).updateDisplayLayout(mMockDisplayLayout);
// No update if the insets state is the same.
- clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
+ clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mMockRestartDialogLayout);
mOnInsetsChangedListenerCaptor.getValue().insetsChanged(new InsetsState(insetsState));
verify(mMockCompatLayout, never()).updateDisplayLayout(mMockDisplayLayout);
verify(mMockLetterboxEduLayout, never()).updateDisplayLayout(mMockDisplayLayout);
+ verify(mMockRestartDialogLayout, never()).updateDisplayLayout(mMockDisplayLayout);
}
@Test
@@ -320,22 +363,26 @@
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
+ verify(mMockRestartDialogLayout).updateVisibility(false);
// Verify button remains hidden while IME is showing.
TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
CAMERA_COMPAT_CONTROL_HIDDEN);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
- verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- false);
- verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- false);
+ verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
+ verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
+ verify(mMockRestartDialogLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
// Verify button is shown after IME is hidden.
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
+ verify(mMockRestartDialogLayout).updateVisibility(true);
}
@Test
@@ -348,22 +395,26 @@
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
+ verify(mMockRestartDialogLayout).updateVisibility(false);
// Verify button remains hidden while keyguard is showing.
TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
CAMERA_COMPAT_CONTROL_HIDDEN);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
- verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- false);
- verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
- false);
+ verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
+ verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
+ verify(mMockRestartDialogLayout).updateCompatInfo(taskInfo, mMockTaskListener,
+ /* canShow= */ false);
// Verify button is shown after keyguard becomes not showing.
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
+ verify(mMockRestartDialogLayout).updateVisibility(true);
}
@Test
@@ -376,20 +427,23 @@
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
+ verify(mMockRestartDialogLayout, times(2)).updateVisibility(false);
- clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
+ clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mMockRestartDialogLayout);
// Verify button remains hidden after keyguard becomes not showing since IME is showing.
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
+ verify(mMockRestartDialogLayout).updateVisibility(false);
// Verify button is shown after IME is not showing.
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
+ verify(mMockRestartDialogLayout).updateVisibility(true);
}
@Test
@@ -402,20 +456,23 @@
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
+ verify(mMockRestartDialogLayout, times(2)).updateVisibility(false);
- clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
+ clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mMockRestartDialogLayout);
// Verify button remains hidden after IME is hidden since keyguard is showing.
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
+ verify(mMockRestartDialogLayout).updateVisibility(false);
// Verify button is shown after keyguard becomes not showing.
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
+ verify(mMockRestartDialogLayout).updateVisibility(true);
}
private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index 7d3e718..5f294d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -31,6 +31,7 @@
import android.app.TaskInfo;
import android.app.TaskInfo.CameraCompatControlState;
import android.testing.AndroidTestingRunner;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.SurfaceControlViewHost;
import android.widget.ImageButton;
@@ -45,12 +46,17 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.function.Consumer;
+
/**
* Tests for {@link CompatUILayout}.
*
@@ -65,20 +71,22 @@
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock private CompatUIController.CompatUICallback mCallback;
+ @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private SurfaceControlViewHost mViewHost;
+ @Mock private CompatUIConfiguration mCompatUIConfiguration;
private CompatUIWindowManager mWindowManager;
private CompatUILayout mLayout;
+ private TaskInfo mTaskInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
-
- mWindowManager = new CompatUIWindowManager(mContext,
- createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN),
- mSyncTransactionQueue, mCallback, mTaskListener,
- new DisplayLayout(), new CompatUIHintsState());
+ mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
+ mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
+ mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+ mCompatUIConfiguration, mOnRestartButtonClicked);
mLayout = (CompatUILayout)
LayoutInflater.from(mContext).inflate(R.layout.compat_ui_layout, null);
@@ -95,8 +103,15 @@
final ImageButton button = mLayout.findViewById(R.id.size_compat_restart_button);
button.performClick();
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> restartCaptor =
+ ArgumentCaptor.forClass(Pair.class);
+
verify(mWindowManager).onRestartButtonClicked();
- verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
+ verify(mOnRestartButtonClicked).accept(restartCaptor.capture());
+ final Pair<TaskInfo, ShellTaskOrganizer.TaskListener> result = restartCaptor.getValue();
+ Assert.assertEquals(mTaskInfo, result.first);
+ Assert.assertEquals(mTaskListener, result.second);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index c4d78bb..f24a7f2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -39,6 +39,7 @@
import android.app.TaskInfo;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
+import android.util.Pair;
import android.view.DisplayInfo;
import android.view.InsetsSource;
import android.view.InsetsState;
@@ -54,12 +55,17 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.function.Consumer;
+
/**
* Tests for {@link CompatUIWindowManager}.
*
@@ -74,20 +80,22 @@
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock private CompatUIController.CompatUICallback mCallback;
+ @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private CompatUILayout mLayout;
@Mock private SurfaceControlViewHost mViewHost;
+ @Mock private CompatUIConfiguration mCompatUIConfiguration;
private CompatUIWindowManager mWindowManager;
+ private TaskInfo mTaskInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
-
- mWindowManager = new CompatUIWindowManager(mContext,
- createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN),
- mSyncTransactionQueue, mCallback, mTaskListener,
- new DisplayLayout(), new CompatUIHintsState());
+ mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
+ mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
+ mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+ mCompatUIConfiguration, mOnRestartButtonClicked);
spyOn(mWindowManager);
doReturn(mLayout).when(mWindowManager).inflateLayout();
@@ -405,7 +413,14 @@
public void testOnRestartButtonClicked() {
mWindowManager.onRestartButtonClicked();
- verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> restartCaptor =
+ ArgumentCaptor.forClass(Pair.class);
+
+ verify(mOnRestartButtonClicked).accept(restartCaptor.capture());
+ final Pair<TaskInfo, ShellTaskOrganizer.TaskListener> result = restartCaptor.getValue();
+ Assert.assertEquals(mTaskInfo, result.first);
+ Assert.assertEquals(mTaskListener, result.second);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogLayoutTest.java
new file mode 100644
index 0000000..e2dcdb0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogLayoutTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+/**
+ * Tests for {@link RestartDialogLayout}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:RestartDialogLayoutTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class RestartDialogLayoutTest extends ShellTestCase {
+
+ @Mock private Runnable mDismissCallback;
+ @Mock private Consumer<Boolean> mRestartCallback;
+
+ private RestartDialogLayout mLayout;
+ private View mDismissButton;
+ private View mRestartButton;
+ private View mDialogContainer;
+ private CheckBox mDontRepeatCheckBox;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mLayout = (RestartDialogLayout)
+ LayoutInflater.from(mContext).inflate(R.layout.letterbox_restart_dialog_layout,
+ null);
+ mDismissButton = mLayout.findViewById(R.id.letterbox_restart_dialog_dismiss_button);
+ mRestartButton = mLayout.findViewById(R.id.letterbox_restart_dialog_restart_button);
+ mDialogContainer = mLayout.findViewById(R.id.letterbox_restart_dialog_container);
+ mDontRepeatCheckBox = mLayout.findViewById(R.id.letterbox_restart_dialog_checkbox);
+ mLayout.setDismissOnClickListener(mDismissCallback);
+ mLayout.setRestartOnClickListener(mRestartCallback);
+ }
+
+ @Test
+ public void testOnFinishInflate() {
+ assertEquals(mLayout.getDialogContainerView(),
+ mLayout.findViewById(R.id.letterbox_restart_dialog_container));
+ assertEquals(mLayout.getDialogTitle(),
+ mLayout.findViewById(R.id.letterbox_restart_dialog_title));
+ assertEquals(mLayout.getBackgroundDimDrawable(), mLayout.getBackground());
+ assertEquals(mLayout.getBackground().getAlpha(), 0);
+ }
+
+ @Test
+ public void testOnDismissButtonClicked() {
+ assertTrue(mDismissButton.performClick());
+
+ verify(mDismissCallback).run();
+ }
+
+ @Test
+ public void testOnRestartButtonClickedWithoutCheckbox() {
+ mDontRepeatCheckBox.setChecked(false);
+ assertTrue(mRestartButton.performClick());
+
+ verify(mRestartCallback).accept(false);
+ }
+
+ @Test
+ public void testOnRestartButtonClickedWithCheckbox() {
+ mDontRepeatCheckBox.setChecked(true);
+ assertTrue(mRestartButton.performClick());
+
+ verify(mRestartCallback).accept(true);
+ }
+
+ @Test
+ public void testOnBackgroundClickedDoesntDismiss() {
+ assertFalse(mLayout.performClick());
+
+ verify(mDismissCallback, never()).run();
+ }
+
+ @Test
+ public void testOnDialogContainerClicked() {
+ assertTrue(mDialogContainer.performClick());
+
+ verify(mDismissCallback, never()).run();
+ verify(mRestartCallback, never()).accept(anyBoolean());
+ }
+
+ @Test
+ public void testSetDismissOnClickListenerNull() {
+ mLayout.setDismissOnClickListener(null);
+
+ assertFalse(mDismissButton.performClick());
+ assertFalse(mLayout.performClick());
+ assertTrue(mDialogContainer.performClick());
+
+ verify(mDismissCallback, never()).run();
+ }
+
+ @Test
+ public void testSetRestartOnClickListenerNull() {
+ mLayout.setRestartOnClickListener(null);
+
+ assertFalse(mRestartButton.performClick());
+ assertFalse(mLayout.performClick());
+ assertTrue(mDialogContainer.performClick());
+
+ verify(mRestartCallback, never()).accept(anyBoolean());
+ }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 5ee8bf3..1a1bebd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -61,7 +61,7 @@
@RunWith(AndroidJUnit4.class)
public final class StageTaskListenerTests extends ShellTestCase {
private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
@Mock
private ShellTaskOrganizer mTaskOrganizer;
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index b1f327c..28bda72 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -55,6 +55,7 @@
host_supported: true,
srcs: [
"ApkAssets.cpp",
+ "ApkParsing.cpp",
"Asset.cpp",
"AssetDir.cpp",
"AssetManager.cpp",
@@ -160,6 +161,7 @@
// Actual tests.
"tests/ApkAssets_test.cpp",
+ "tests/ApkParsing_test.cpp",
"tests/AppAsLib_test.cpp",
"tests/Asset_test.cpp",
"tests/AssetManager2_test.cpp",
diff --git a/libs/androidfw/ApkParsing.cpp b/libs/androidfw/ApkParsing.cpp
new file mode 100644
index 0000000..cf4fbb9
--- /dev/null
+++ b/libs/androidfw/ApkParsing.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "androidfw/ApkParsing.h"
+#include <algorithm>
+#include <array>
+#include <stdlib.h>
+#include <string_view>
+#include <sys/types.h>
+
+const std::string_view APK_LIB = "lib/";
+const size_t APK_LIB_LEN = APK_LIB.size();
+
+const std::string_view LIB_PREFIX = "/lib";
+const size_t LIB_PREFIX_LEN = LIB_PREFIX.size();
+
+const std::string_view LIB_SUFFIX = ".so";
+const size_t LIB_SUFFIX_LEN = LIB_SUFFIX.size();
+
+static const std::array<std::string_view, 2> abis = {"arm64-v8a", "x86_64"};
+
+namespace android::util {
+const char* ValidLibraryPathLastSlash(const char* fileName, bool suppress64Bit, bool debuggable) {
+ // Make sure the filename is at least to the minimum library name size.
+ const size_t fileNameLen = strlen(fileName);
+ static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
+ if (fileNameLen < minLength) {
+ return nullptr;
+ }
+
+ const char* lastSlash = strrchr(fileName, '/');
+ if (!lastSlash) {
+ return nullptr;
+ }
+
+ // Skip directories.
+ if (*(lastSlash + 1) == 0) {
+ return nullptr;
+ }
+
+ // Make sure the filename is safe.
+ if (!isFilenameSafe(lastSlash + 1)) {
+ return nullptr;
+ }
+
+ // Make sure there aren't subdirectories
+ const char* abiOffset = fileName + APK_LIB_LEN;
+ const size_t abiSize = lastSlash - abiOffset;
+ if (memchr(abiOffset, '/', abiSize)) {
+ return nullptr;
+ }
+
+ if (!debuggable) {
+ // Make sure the filename starts with lib and ends with ".so".
+ if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX.data(), LIB_SUFFIX_LEN) != 0
+ || strncmp(lastSlash, LIB_PREFIX.data(), LIB_PREFIX_LEN) != 0) {
+ return nullptr;
+ }
+ }
+
+ // Don't include 64 bit versions if they are suppressed
+ if (suppress64Bit && std::find(abis.begin(), abis.end(), std::string_view(
+ fileName + APK_LIB_LEN, lastSlash - fileName - APK_LIB_LEN)) != abis.end()) {
+ return nullptr;
+ }
+
+ return lastSlash;
+}
+
+bool isFilenameSafe(const char* filename) {
+ off_t offset = 0;
+ for (;;) {
+ switch (*(filename + offset)) {
+ case 0:
+ // Null.
+ // If we've reached the end, all the other characters are good.
+ return true;
+
+ case 'A' ... 'Z':
+ case 'a' ... 'z':
+ case '0' ... '9':
+ case '+':
+ case ',':
+ case '-':
+ case '.':
+ case '/':
+ case '=':
+ case '_':
+ offset++;
+ break;
+
+ default:
+ // We found something that is not good.
+ return false;
+ }
+ }
+ // Should not reach here.
+}
+}
\ No newline at end of file
diff --git a/libs/androidfw/include/androidfw/ApkParsing.h b/libs/androidfw/include/androidfw/ApkParsing.h
new file mode 100644
index 0000000..194eaae
--- /dev/null
+++ b/libs/androidfw/include/androidfw/ApkParsing.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <string_view>
+#include <sys/types.h>
+
+extern const std::string_view APK_LIB;
+extern const size_t APK_LIB_LEN;
+
+namespace android::util {
+// Checks if filename is a valid library path and returns a pointer to the last slash in the path
+// if it is, nullptr otherwise
+const char* ValidLibraryPathLastSlash(const char* filename, bool suppress64Bit, bool debuggable);
+
+// Equivalent to android.os.FileUtils.isFilenameSafe
+bool isFilenameSafe(const char* filename);
+}
diff --git a/libs/androidfw/tests/ApkParsing_test.cpp b/libs/androidfw/tests/ApkParsing_test.cpp
new file mode 100644
index 0000000..4aab0a1
--- /dev/null
+++ b/libs/androidfw/tests/ApkParsing_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "androidfw/ApkParsing.h"
+
+#include "android-base/test_utils.h"
+
+#include "TestHelpers.h"
+
+using ::testing::Eq;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+namespace android {
+TEST(ApkParsingTest, ValidArm64Path) {
+ const char* path = "lib/arm64-v8a/library.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, NotNull());
+ ASSERT_THAT(lastSlash, Eq(path + 13));
+}
+
+TEST(ApkParsingTest, ValidArm64PathButSuppressed) {
+ const char* path = "lib/arm64-v8a/library.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, true, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
+
+TEST(ApkParsingTest, ValidArm32Path) {
+ const char* path = "lib/armeabi-v7a/library.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, NotNull());
+ ASSERT_THAT(lastSlash, Eq(path + 15));
+}
+
+TEST(ApkParsingTest, InvalidMustStartWithLib) {
+ const char* path = "lib/arm64-v8a/random.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
+
+TEST(ApkParsingTest, InvalidMustEndInSo) {
+ const char* path = "lib/arm64-v8a/library.txt";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
+
+TEST(ApkParsingTest, InvalidCharacter) {
+ const char* path = "lib/arm64-v8a/lib#.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
+
+TEST(ApkParsingTest, InvalidSubdirectories) {
+ const char* path = "lib/arm64-v8a/anything/library.so";
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ ASSERT_THAT(lastSlash, IsNull());
+}
+}
\ No newline at end of file
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 9112b1b..8d4bda2 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -78,7 +78,6 @@
"external/skia/src/utils",
"external/skia/src/gpu",
"external/skia/src/shaders",
- "external/skia/modules/skottie",
],
},
host: {
@@ -388,7 +387,6 @@
"external/skia/src/effects",
"external/skia/src/image",
"external/skia/src/images",
- "external/skia/modules/skottie",
],
shared_libs: [
@@ -420,7 +418,6 @@
"jni/BitmapRegionDecoder.cpp",
"jni/GIFMovie.cpp",
"jni/GraphicsStatsService.cpp",
- "jni/LottieDrawable.cpp",
"jni/Movie.cpp",
"jni/MovieImpl.cpp",
"jni/pdf/PdfDocument.cpp",
@@ -528,7 +525,6 @@
"hwui/BlurDrawLooper.cpp",
"hwui/Canvas.cpp",
"hwui/ImageDecoder.cpp",
- "hwui/LottieDrawable.cpp",
"hwui/MinikinSkia.cpp",
"hwui/MinikinUtils.cpp",
"hwui/PaintImpl.cpp",
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1e0c359..d0124f5 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -740,10 +740,6 @@
return imgDrawable->drawStaging(mCanvas);
}
-void SkiaCanvas::drawLottie(LottieDrawable* lottieDrawable) {
- lottieDrawable->drawStaging(mCanvas);
-}
-
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
vectorDrawable->drawStaging(this);
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 1524dff..f2c286a 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -144,7 +144,6 @@
float dstTop, float dstRight, float dstBottom,
const Paint* paint) override;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
- virtual void drawLottie(LottieDrawable* lottieDrawable) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index b1aa1947..f57d80c 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -37,7 +37,6 @@
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_ImageDecoder(JNIEnv*);
extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv*);
-extern int register_android_graphics_drawable_LottieDrawable(JNIEnv*);
extern int register_android_graphics_Interpolator(JNIEnv* env);
extern int register_android_graphics_MaskFilter(JNIEnv* env);
extern int register_android_graphics_Movie(JNIEnv* env);
@@ -118,7 +117,6 @@
REG_JNI(register_android_graphics_HardwareRendererObserver),
REG_JNI(register_android_graphics_ImageDecoder),
REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
- REG_JNI(register_android_graphics_drawable_LottieDrawable),
REG_JNI(register_android_graphics_Interpolator),
REG_JNI(register_android_graphics_MaskFilter),
REG_JNI(register_android_graphics_Matrix),
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 07e2fe2..2a20191 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -60,7 +60,6 @@
typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc;
class AnimatedImageDrawable;
-class LottieDrawable;
class Bitmap;
class Paint;
struct Typeface;
@@ -243,7 +242,6 @@
const Paint* paint) = 0;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
- virtual void drawLottie(LottieDrawable* lottieDrawable) = 0;
virtual void drawPicture(const SkPicture& picture) = 0;
/**
diff --git a/libs/hwui/hwui/LottieDrawable.cpp b/libs/hwui/hwui/LottieDrawable.cpp
deleted file mode 100644
index 92dc51e..0000000
--- a/libs/hwui/hwui/LottieDrawable.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LottieDrawable.h"
-
-#include <SkTime.h>
-#include <log/log.h>
-#include <pipeline/skia/SkiaUtils.h>
-
-namespace android {
-
-sk_sp<LottieDrawable> LottieDrawable::Make(sk_sp<skottie::Animation> animation, size_t bytesUsed) {
- if (animation) {
- return sk_sp<LottieDrawable>(new LottieDrawable(std::move(animation), bytesUsed));
- }
- return nullptr;
-}
-LottieDrawable::LottieDrawable(sk_sp<skottie::Animation> animation, size_t bytesUsed)
- : mAnimation(std::move(animation)), mBytesUsed(bytesUsed) {}
-
-bool LottieDrawable::start() {
- if (mRunning) {
- return false;
- }
-
- mRunning = true;
- return true;
-}
-
-bool LottieDrawable::stop() {
- bool wasRunning = mRunning;
- mRunning = false;
- return wasRunning;
-}
-
-bool LottieDrawable::isRunning() {
- return mRunning;
-}
-
-// TODO: Check to see if drawable is actually dirty
-bool LottieDrawable::isDirty() {
- return true;
-}
-
-void LottieDrawable::onDraw(SkCanvas* canvas) {
- if (mRunning) {
- const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- nsecs_t t = 0;
- if (mStartTime == 0) {
- mStartTime = currentTime;
- } else {
- t = currentTime - mStartTime;
- }
- double seekTime = std::fmod((double)t * 1e-9, mAnimation->duration());
- mAnimation->seekFrameTime(seekTime);
- mAnimation->render(canvas);
- }
-}
-
-void LottieDrawable::drawStaging(SkCanvas* canvas) {
- onDraw(canvas);
-}
-
-SkRect LottieDrawable::onGetBounds() {
- // We do not actually know the bounds, so give a conservative answer.
- return SkRectMakeLargest();
-}
-
-} // namespace android
diff --git a/libs/hwui/hwui/LottieDrawable.h b/libs/hwui/hwui/LottieDrawable.h
deleted file mode 100644
index 9cc34bf..0000000
--- a/libs/hwui/hwui/LottieDrawable.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <SkDrawable.h>
-#include <Skottie.h>
-#include <utils/Timers.h>
-
-class SkCanvas;
-
-namespace android {
-
-/**
- * Native component of android.graphics.drawable.LottieDrawable.java.
- * This class can be drawn into Canvas.h and maintains the state needed to drive
- * the animation from the RenderThread.
- */
-class LottieDrawable : public SkDrawable {
-public:
- static sk_sp<LottieDrawable> Make(sk_sp<skottie::Animation> animation, size_t bytes);
-
- // Draw to software canvas
- void drawStaging(SkCanvas* canvas);
-
- // Returns true if the animation was started; false otherwise (e.g. it was
- // already running)
- bool start();
- // Returns true if the animation was stopped; false otherwise (e.g. it was
- // already stopped)
- bool stop();
- bool isRunning();
-
- // TODO: Is dirty should take in a time til next frame to determine if it is dirty
- bool isDirty();
-
- SkRect onGetBounds() override;
-
- size_t byteSize() const { return sizeof(*this) + mBytesUsed; }
-
-protected:
- void onDraw(SkCanvas* canvas) override;
-
-private:
- LottieDrawable(sk_sp<skottie::Animation> animation, size_t bytes_used);
-
- sk_sp<skottie::Animation> mAnimation;
- bool mRunning = false;
- // The start time for the drawable itself.
- nsecs_t mStartTime = 0;
- const size_t mBytesUsed = 0;
-};
-
-} // namespace android
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 540abec..c68a6b9 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -422,6 +422,11 @@
return ret;
}
+static jint Bitmap_getAshmemFd(JNIEnv* env, jobject, jlong bitmapHandle) {
+ LocalScopedBitmap bitmap(bitmapHandle);
+ return (bitmap.valid()) ? bitmap->bitmap().getAshmemFd() : -1;
+}
+
static void Bitmap_destruct(BitmapWrapper* bitmap) {
delete bitmap;
}
@@ -1257,6 +1262,7 @@
(void*)Bitmap_copyAshmem },
{ "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
(void*)Bitmap_copyAshmemConfig },
+ { "nativeGetAshmemFD", "(J)I", (void*)Bitmap_getAshmemFd },
{ "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
{ "nativeRecycle", "(J)V", (void*)Bitmap_recycle },
{ "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
diff --git a/libs/hwui/jni/LottieDrawable.cpp b/libs/hwui/jni/LottieDrawable.cpp
deleted file mode 100644
index fb6eede..0000000
--- a/libs/hwui/jni/LottieDrawable.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <SkRect.h>
-#include <Skottie.h>
-#include <hwui/Canvas.h>
-#include <hwui/LottieDrawable.h>
-
-#include "GraphicsJNI.h"
-#include "Utils.h"
-
-using namespace android;
-
-static jclass gLottieDrawableClass;
-
-static jlong LottieDrawable_nCreate(JNIEnv* env, jobject, jstring jjson) {
- const ScopedUtfChars cstr(env, jjson);
- // TODO(b/259267150) provide more accurate byteSize
- size_t bytes = strlen(cstr.c_str());
- auto animation = skottie::Animation::Builder().make(cstr.c_str(), bytes);
- sk_sp<LottieDrawable> drawable(LottieDrawable::Make(std::move(animation), bytes));
- if (!drawable) {
- return 0;
- }
- return reinterpret_cast<jlong>(drawable.release());
-}
-
-static void LottieDrawable_destruct(LottieDrawable* drawable) {
- SkSafeUnref(drawable);
-}
-
-static jlong LottieDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(&LottieDrawable_destruct));
-}
-
-static void LottieDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jlong canvasPtr) {
- auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
- auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- canvas->drawLottie(drawable);
-}
-
-static jboolean LottieDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
- auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
- return drawable->isRunning();
-}
-
-static jboolean LottieDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
- auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
- return drawable->start();
-}
-
-static jboolean LottieDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
- auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
- return drawable->stop();
-}
-
-static jlong LottieDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
- auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
- return drawable->byteSize();
-}
-
-static const JNINativeMethod gLottieDrawableMethods[] = {
- {"nCreate", "(Ljava/lang/String;)J", (void*)LottieDrawable_nCreate},
- {"nNativeByteSize", "(J)J", (void*)LottieDrawable_nNativeByteSize},
- {"nGetNativeFinalizer", "()J", (void*)LottieDrawable_nGetNativeFinalizer},
- {"nDraw", "(JJ)V", (void*)LottieDrawable_nDraw},
- {"nIsRunning", "(J)Z", (void*)LottieDrawable_nIsRunning},
- {"nStart", "(J)Z", (void*)LottieDrawable_nStart},
- {"nStop", "(J)Z", (void*)LottieDrawable_nStop},
-};
-
-int register_android_graphics_drawable_LottieDrawable(JNIEnv* env) {
- gLottieDrawableClass = reinterpret_cast<jclass>(
- env->NewGlobalRef(FindClassOrDie(env, "android/graphics/drawable/LottieDrawable")));
-
- return android::RegisterMethodsOrDie(env, "android/graphics/drawable/LottieDrawable",
- gLottieDrawableMethods, NELEM(gLottieDrawableMethods));
-}
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 3f4d004..5892308 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -822,6 +822,11 @@
proxy->notifyCallbackPending();
}
+static void android_view_ThreadedRenderer_notifyExpensiveFrame(JNIEnv*, jclass, jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->notifyExpensiveFrame();
+}
+
// Plumbs the display density down to DeviceInfo.
static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) {
// Convert from dpi to density-independent pixels.
@@ -1000,6 +1005,8 @@
(void*)android_view_ThreadedRenderer_setRtAnimationsEnabled},
{"nNotifyCallbackPending", "(J)V",
(void*)android_view_ThreadedRenderer_notifyCallbackPending},
+ {"nNotifyExpensiveFrame", "(J)V",
+ (void*)android_view_ThreadedRenderer_notifyExpensiveFrame},
};
static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index f0dc5eb..fcfc4f8 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -146,16 +146,6 @@
}
}
- for (auto& lottie : mLotties) {
- // If any animated image in the display list needs updated, then damage the node.
- if (lottie->isDirty()) {
- isDirty = true;
- }
- if (lottie->isRunning()) {
- info.out.hasAnimations = true;
- }
- }
-
for (auto& [vectorDrawable, cachedMatrix] : mVectorDrawables) {
// If any vector drawable in the display list needs update, damage the node.
if (vectorDrawable->isDirty()) {
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 39217fc..2a67734 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -22,7 +22,6 @@
#include "RenderNodeDrawable.h"
#include "TreeInfo.h"
#include "hwui/AnimatedImageDrawable.h"
-#include "hwui/LottieDrawable.h"
#include "utils/LinearAllocator.h"
#include "utils/Pair.h"
@@ -187,8 +186,6 @@
return mHasHolePunches;
}
- // TODO(b/257304231): create common base class for Lotties and AnimatedImages
- std::vector<LottieDrawable*> mLotties;
std::vector<AnimatedImageDrawable*> mAnimatedImages;
DisplayListData mDisplayList;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 08f0291..c9d79ab 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -189,11 +189,6 @@
#endif
}
-void SkiaRecordingCanvas::drawLottie(LottieDrawable* lottie) {
- drawDrawable(lottie);
- mDisplayList->mLotties.push_back(lottie);
-}
-
void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mRecorder.drawVectorDrawable(tree);
SkMatrix mat;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index c823d8d..7844e2c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -78,7 +78,6 @@
uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawRipple(const RippleDrawableParams& params) override;
- virtual void drawLottie(LottieDrawable* lottieDrawable) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
virtual void enableZ(bool enableZ) override;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 1c76884..23611ef 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -19,7 +19,6 @@
#include <GrContextOptions.h>
#include <SkExecutor.h>
#include <SkGraphics.h>
-#include <SkMathPriv.h>
#include <math.h>
#include <utils/Trace.h>
@@ -47,13 +46,23 @@
setupCacheLimits();
}
+static inline int countLeadingZeros(uint32_t mask) {
+ // __builtin_clz(0) is undefined, so we have to detect that case.
+ return mask ? __builtin_clz(mask) : 32;
+}
+
+// Return the smallest power-of-2 >= n.
+static inline uint32_t nextPowerOfTwo(uint32_t n) {
+ return n ? (1 << (32 - countLeadingZeros(n - 1))) : 1;
+}
+
void CacheManager::setupCacheLimits() {
mMaxResourceBytes = mMaxSurfaceArea * mMemoryPolicy.surfaceSizeMultiplier;
mBackgroundResourceBytes = mMaxResourceBytes * mMemoryPolicy.backgroundRetentionPercent;
// This sets the maximum size for a single texture atlas in the GPU font cache. If
// necessary, the cache can allocate additional textures that are counted against the
// total cache limits provided to Skia.
- mMaxGpuFontAtlasBytes = GrNextSizePow2(mMaxSurfaceArea);
+ mMaxGpuFontAtlasBytes = nextPowerOfTwo(mMaxSurfaceArea);
// This sets the maximum size of the CPU font cache to be at least the same size as the
// total number of GPU font caches (i.e. 4 separate GPU atlases).
mMaxCpuFontCacheBytes = std::max(mMaxGpuFontAtlasBytes * 4, SkGraphics::GetFontCacheLimit());
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b769f8d..6f549dc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -194,6 +194,8 @@
ATRACE_CALL();
if (window) {
+ // Ensure the hint session is running here, away from any critical paths
+ mHintSessionWrapper.init();
mNativeSurface = std::make_unique<ReliableSurface>(window);
mNativeSurface->init();
if (enableTimeout) {
@@ -1021,6 +1023,10 @@
mHintSessionWrapper.sendLoadResetHint();
}
+void CanvasContext::sendLoadIncreaseHint() {
+ mHintSessionWrapper.sendLoadIncreaseHint();
+}
+
void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
mSyncDelayDuration = duration;
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3f796d9..a274d2f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -223,6 +223,8 @@
void sendLoadResetHint();
+ void sendLoadIncreaseHint();
+
void setSyncDelayDuration(nsecs_t duration);
private:
diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp
index 94c9d94..8c9f65f 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.cpp
+++ b/libs/hwui/renderthread/HintSessionWrapper.cpp
@@ -95,17 +95,13 @@
}
}
-bool HintSessionWrapper::useHintSession() {
- if (!Properties::useHintManager || !Properties::isDrawingEnabled()) return false;
- if (mHintSession) return true;
- // If session does not exist, create it;
- // this defers session creation until we try to actually use it.
- if (!mSessionValid) return false;
- return init();
-}
-
bool HintSessionWrapper::init() {
- if (mUiThreadId < 0 || mRenderThreadId < 0) return false;
+ // If it already exists, broke last time we tried this, shouldn't be running, or
+ // has bad argument values, don't even bother
+ if (mHintSession != nullptr || !mSessionValid || !Properties::useHintManager ||
+ !Properties::isDrawingEnabled() || mUiThreadId < 0 || mRenderThreadId < 0) {
+ return false;
+ }
// Assume that if we return before the end, it broke
mSessionValid = false;
@@ -130,7 +126,7 @@
}
void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
- if (!useHintSession()) return;
+ if (mHintSession == nullptr) return;
targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
if (targetWorkDurationNanos != mLastTargetWorkDuration &&
targetWorkDurationNanos > kSanityCheckLowerBound &&
@@ -142,7 +138,7 @@
}
void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
- if (!useHintSession()) return;
+ if (mHintSession == nullptr) return;
if (actualDurationNanos > kSanityCheckLowerBound &&
actualDurationNanos < kSanityCheckUpperBound) {
gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
@@ -150,7 +146,7 @@
}
void HintSessionWrapper::sendLoadResetHint() {
- if (!useHintSession()) return;
+ if (mHintSession == nullptr) return;
nsecs_t now = systemTime();
if (now - mLastFrameNotification > kResetHintTimeout) {
gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
@@ -158,6 +154,11 @@
mLastFrameNotification = now;
}
+void HintSessionWrapper::sendLoadIncreaseHint() {
+ if (mHintSession == nullptr) return;
+ gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP));
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h
index fcbc101..f2f1298 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.h
+++ b/libs/hwui/renderthread/HintSessionWrapper.h
@@ -33,10 +33,10 @@
void updateTargetWorkDuration(long targetDurationNanos);
void reportActualWorkDuration(long actualDurationNanos);
void sendLoadResetHint();
+ void sendLoadIncreaseHint();
+ bool init();
private:
- bool useHintSession();
- bool init();
APerformanceHintSession* mHintSession = nullptr;
nsecs_t mLastFrameNotification = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ed01e32..5edb0b1 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -254,6 +254,10 @@
mRenderThread.queue().post([this]() { mContext->sendLoadResetHint(); });
}
+void RenderProxy::notifyExpensiveFrame() {
+ mRenderThread.queue().post([this]() { mContext->sendLoadIncreaseHint(); });
+}
+
void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
mRenderThread.queue().runSync([&]() {
std::lock_guard lock(mRenderThread.getJankDataMutex());
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 17cf665..2aafe76 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -112,6 +112,7 @@
void stopDrawing();
void notifyFramePending();
void notifyCallbackPending();
+ void notifyExpensiveFrame();
void dumpProfileInfo(int fd, int dumpFlags);
// Not exported, only used for testing
diff --git a/media/aidl/android/media/soundtrigger_middleware/OWNERS b/media/aidl/android/media/soundtrigger_middleware/OWNERS
index e5d0370..01b2cb9 100644
--- a/media/aidl/android/media/soundtrigger_middleware/OWNERS
+++ b/media/aidl/android/media/soundtrigger_middleware/OWNERS
@@ -1,2 +1,2 @@
-ytai@google.com
+atneya@google.com
elaurent@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 813929e..a4d5606 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -20,6 +20,7 @@
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
+import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -407,7 +408,7 @@
public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
/** @hide Used to identify the volume of audio streams for virtual assistant */
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
/** Number of audio streams */
@@ -1038,7 +1039,7 @@
/** @hide */
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setMasterMute(boolean mute, int flags) {
final IAudioService service = getService();
try {
@@ -1346,16 +1347,12 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- service.setVolumeIndexForAttributes(attr, index, flags,
- getContext().getOpPackageName(), getContext().getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ setVolumeGroupVolumeIndex(groupId, index, flags);
}
/**
@@ -1370,15 +1367,12 @@
*/
@SystemApi
@IntRange(from = 0)
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- return service.getVolumeIndexForAttributes(attr);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupVolumeIndex(groupId);
}
/**
@@ -1391,15 +1385,12 @@
*/
@SystemApi
@IntRange(from = 0)
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- return service.getMaxVolumeIndexForAttributes(attr);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupMaxVolumeIndex(groupId);
}
/**
@@ -1412,12 +1403,186 @@
*/
@SystemApi
@IntRange(from = 0)
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupMinVolumeIndex(groupId);
+ }
+
+ /**
+ * Returns the volume group id associated to the given {@link AudioAttributes}.
+ *
+ * @param attributes The {@link AudioAttributes} to consider.
+ * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given
+ * {@link AudioAttributes} if found,
+ * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
+ */
+ public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
+ Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
+ return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
+ /* fallbackOnDefault= */ false);
+ }
+
+ /**
+ * Sets the volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
+ * to retrieve the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @param index The volume index to set. See
+ * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
+ * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
+ * @param flags One or more flags.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public void setVolumeGroupVolumeIndex(int groupId, int index, int flags) {
+ final IAudioService service = getService();
try {
- return service.getMinVolumeIndexForAttributes(attr);
+ service.setVolumeGroupVolumeIndex(groupId, index, flags,
+ getContext().getOpPackageName(), getContext().getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
+ * to retrieve the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The current volume index for the stream.
+ * @hide
+ */
+ @SystemApi
+ @IntRange(from = 0)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public int getVolumeGroupVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the maximum volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
+ * to retrieve the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The maximum valid volume index for the {@link AudioAttributes}.
+ * @hide
+ */
+ @SystemApi
+ @IntRange(from = 0)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public int getVolumeGroupMaxVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupMaxVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the minimum volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
+ * to retrieve the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The minimum valid volume index for the {@link AudioAttributes}.
+ * @hide
+ */
+ @SystemApi
+ @IntRange(from = 0)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public int getVolumeGroupMinVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupMinVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adjusts the volume of a particular group associated to given id by one step in a direction.
+ * <p> If the volume group is associated to a stream type, it fallbacks on
+ * {@link #adjustStreamVolume(int, int, int)} for compatibility reason.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
+ * the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @param direction The direction to adjust the volume. One of
+ * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
+ * {@link #ADJUST_SAME}.
+ * @param flags One or more flags.
+ * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
+ * is not granted notification policy access.
+ */
+ public void adjustVolumeGroupVolume(int groupId, int direction, int flags) {
+ IAudioService service = getService();
+ try {
+ service.adjustVolumeGroupVolume(groupId, direction, flags,
+ getContext().getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get last audible volume of the group associated to given id before it was muted.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
+ * the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return current volume if not muted, volume before muted otherwise.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
+ @IntRange(from = 0)
+ public int getLastAudibleVolumeGroupVolume(int groupId) {
+ IAudioService service = getService();
+ try {
+ return service.getLastAudibleVolumeGroupVolume(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current mute state for a particular volume group associated to the given id.
+ * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
+ * the volume group id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id.
+ * @see #adjustVolumeGroupVolume(int, int, int)
+ */
+ public boolean isVolumeGroupMuted(int groupId) {
+ IAudioService service = getService();
+ try {
+ return service.isVolumeGroupMuted(groupId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1429,7 +1594,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
Objects.requireNonNull(systemUsages, "systemUsages must not be null");
final IAudioService service = getService();
@@ -1446,7 +1611,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
final IAudioService service = getService();
try {
@@ -1555,7 +1720,7 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@UnsupportedAppUsage
public void forceVolumeControlStream(int streamType) {
final IAudioService service = getService();
@@ -1752,7 +1917,7 @@
* @return true if the operation was successful, false otherwise
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
@NonNull AudioDeviceAttributes device) {
return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
@@ -1768,7 +1933,7 @@
* device set for example)
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
Objects.requireNonNull(strategy);
try {
@@ -1791,7 +1956,7 @@
* ever set or if the strategy is invalid
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Nullable
public AudioDeviceAttributes getPreferredDeviceForStrategy(
@NonNull AudioProductStrategy strategy) {
@@ -1813,7 +1978,7 @@
* @return true if the operation was successful, false otherwise
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
@NonNull List<AudioDeviceAttributes> devices) {
Objects.requireNonNull(strategy);
@@ -1843,7 +2008,7 @@
* @return list of the preferred devices for that strategy
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@NonNull
public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
@NonNull AudioProductStrategy strategy) {
@@ -1867,7 +2032,7 @@
* @return true if the operation was successful, false otherwise
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
@NonNull AudioDeviceAttributes device) {
Objects.requireNonNull(strategy);
@@ -1891,7 +2056,7 @@
* device set for example)
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
@NonNull AudioDeviceAttributes device) {
Objects.requireNonNull(strategy);
@@ -1913,7 +2078,7 @@
* @return list of non-default devices for the strategy
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@NonNull
public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
@NonNull AudioProductStrategy strategy) {
@@ -1996,7 +2161,7 @@
* Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Deprecated
public void addOnPreferredDeviceForStrategyChangedListener(
@NonNull @CallbackExecutor Executor executor,
@@ -2013,7 +2178,7 @@
* AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Deprecated
public void removeOnPreferredDeviceForStrategyChangedListener(
@NonNull OnPreferredDeviceForStrategyChangedListener listener) {
@@ -2028,7 +2193,7 @@
* @throws SecurityException if the caller doesn't hold the required permission
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void addOnPreferredDevicesForStrategyChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnPreferredDevicesForStrategyChangedListener listener)
@@ -2046,7 +2211,7 @@
* @param listener
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void removeOnPreferredDevicesForStrategyChangedListener(
@NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Objects.requireNonNull(listener);
@@ -2092,7 +2257,7 @@
* @throws SecurityException if the caller doesn't hold the required permission
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void addOnNonDefaultDevicesForStrategyChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
@@ -2112,7 +2277,7 @@
* @param listener
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void removeOnNonDefaultDevicesForStrategyChangedListener(
@NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
Objects.requireNonNull(listener);
@@ -2206,7 +2371,7 @@
* @return true if the operation was successful, false otherwise
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
@NonNull AudioDeviceAttributes device) {
return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
@@ -2220,7 +2385,7 @@
* device set for example)
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean clearPreferredDevicesForCapturePreset(
@MediaRecorder.SystemSource int capturePreset) {
if (!MediaRecorder.isValidAudioSource(capturePreset)) {
@@ -2243,7 +2408,7 @@
*/
@NonNull
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
@MediaRecorder.SystemSource int capturePreset) {
if (!MediaRecorder.isValidAudioSource(capturePreset)) {
@@ -2315,7 +2480,7 @@
* @throws SecurityException if the caller doesn't hold the required permission
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void addOnPreferredDevicesForCapturePresetChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
@@ -2341,7 +2506,7 @@
* @param listener
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void removeOnPreferredDevicesForCapturePresetChangedListener(
@NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
Objects.requireNonNull(listener);
@@ -2785,7 +2950,7 @@
/**
* Start bluetooth SCO audio connection.
* <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+ * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
* <p>This method can be used by applications wanting to send and received audio
* to/from a bluetooth SCO headset while the phone is not in call.
* <p>As the SCO connection establishment can take several seconds,
@@ -2842,7 +3007,7 @@
* @hide
* Start bluetooth SCO audio connection in virtual call mode.
* <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+ * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
* <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
* Telephony and communication applications (VoIP, Video Chat) should preferably select
* virtual call mode.
@@ -2866,7 +3031,7 @@
/**
* Stop bluetooth SCO audio connection.
* <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+ * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
* <p>This method must be called by applications having requested the use of
* bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
* connection or if connection fails.
@@ -3454,7 +3619,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setHfpEnabled(boolean enable) {
AudioSystem.setParameters("hfp_enable=" + enable);
}
@@ -3463,7 +3628,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setHfpVolume(int volume) {
AudioSystem.setParameters("hfp_volume=" + volume);
}
@@ -3472,7 +3637,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setHfpSamplingRate(int rate) {
AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
}
@@ -3481,7 +3646,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
boolean hasWbsEnabled) {
AudioSystem.setParameters("bt_headset_name=" + name
@@ -3493,7 +3658,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setA2dpSuspended(boolean enable) {
AudioSystem.setParameters("A2dpSuspended=" + enable);
}
@@ -3506,7 +3671,7 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setLeAudioSuspended(boolean enable) {
AudioSystem.setParameters("LeAudioSuspended=" + enable);
}
@@ -4316,7 +4481,7 @@
* @throws IllegalArgumentException
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public int requestAudioFocus(OnAudioFocusChangeListener l,
@NonNull AudioAttributes requestAttributes,
int durationHint,
@@ -4357,8 +4522,8 @@
*/
@SystemApi
@RequiresPermission(anyOf= {
- android.Manifest.permission.MODIFY_PHONE_STATE,
- android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ Manifest.permission.MODIFY_PHONE_STATE,
+ Manifest.permission.MODIFY_AUDIO_ROUTING
})
public int requestAudioFocus(OnAudioFocusChangeListener l,
@NonNull AudioAttributes requestAttributes,
@@ -4502,7 +4667,7 @@
* @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
if (afr == null) {
throw new NullPointerException("Illegal null AudioFocusRequest");
@@ -4689,7 +4854,7 @@
* @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
@FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
if (afi == null) {
@@ -4728,7 +4893,7 @@
* @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
@NonNull AudioPolicy ap) {
if (afi == null) {
@@ -4988,11 +5153,11 @@
* @param policy the non-null {@link AudioPolicy} to register.
* @return {@link #ERROR} if there was an error communicating with the registration service
* or if the user doesn't have the required
- * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
+ * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
* {@link #SUCCESS} otherwise.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public int registerAudioPolicy(@NonNull AudioPolicy policy) {
return registerAudioPolicyStatic(policy);
}
@@ -5026,7 +5191,7 @@
* @param policy the non-null {@link AudioPolicy} to unregister.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
unregisterAudioPolicyAsyncStatic(policy);
}
@@ -5052,7 +5217,7 @@
* @param policy the non-null {@link AudioPolicy} to unregister.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
final IAudioService service = getService();
@@ -5853,8 +6018,8 @@
*/
@SystemApi
@RequiresPermission(anyOf = {
- android.Manifest.permission.MODIFY_AUDIO_ROUTING,
- android.Manifest.permission.QUERY_AUDIO_STATE
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
})
public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
@@ -5929,8 +6094,8 @@
*/
@SystemApi
@RequiresPermission(anyOf = {
- android.Manifest.permission.MODIFY_AUDIO_ROUTING,
- android.Manifest.permission.QUERY_AUDIO_STATE
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
})
public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
@NonNull @CallbackExecutor Executor executor,
@@ -5960,8 +6125,8 @@
*/
@SystemApi
@RequiresPermission(anyOf = {
- android.Manifest.permission.MODIFY_AUDIO_ROUTING,
- android.Manifest.permission.QUERY_AUDIO_STATE
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
})
public void removeOnDevicesForAttributesChangedListener(
@NonNull OnDevicesForAttributesChangedListener listener) {
@@ -6119,7 +6284,10 @@
* @param deviceVolumeBehavior one of the device behaviors
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS
+ })
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@DeviceVolumeBehavior int deviceVolumeBehavior) {
// verify arguments (validity of device type is enforced in server)
@@ -6143,8 +6311,9 @@
*/
@SystemApi
@RequiresPermission(anyOf = {
- android.Manifest.permission.MODIFY_AUDIO_ROUTING,
- android.Manifest.permission.QUERY_AUDIO_STATE
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE,
+ Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS
})
public @DeviceVolumeBehavior
int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
@@ -6165,8 +6334,9 @@
*/
@TestApi
@RequiresPermission(anyOf = {
- android.Manifest.permission.MODIFY_AUDIO_ROUTING,
- android.Manifest.permission.QUERY_AUDIO_STATE
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE,
+ Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS
})
public boolean isFullVolumeDevice() {
final AudioAttributes attributes = new AudioAttributes.Builder()
@@ -6189,7 +6359,7 @@
* {@hide}
*/
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
setWiredDeviceConnectionState(attributes, state);
@@ -6202,7 +6372,7 @@
* {@hide}
*/
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
final IAudioService service = getService();
try {
@@ -6220,7 +6390,7 @@
* {@hide}
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
boolean connected) {
try {
@@ -6243,7 +6413,7 @@
* {@hide}
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
@Nullable BluetoothDevice previousDevice,
@NonNull BluetoothProfileConnectionInfo info) {
@@ -6363,7 +6533,7 @@
* or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setAdditionalOutputDeviceDelay(
@NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Objects.requireNonNull(device);
@@ -6522,7 +6692,7 @@
* @return the RS2 value used for momentary exposure warnings
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public float getRs2Value() {
try {
return getService().getRs2Value();
@@ -6536,7 +6706,7 @@
* Sets the RS2 value used for momentary exposure warnings
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void setRs2Value(float rs2Value) {
try {
getService().setRs2Value(rs2Value);
@@ -6550,7 +6720,7 @@
* @return the current computed sound dose value
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public float getCsd() {
try {
return getService().getCsd();
@@ -6564,7 +6734,7 @@
* Sets the computed sound dose value to {@code csd}
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void setCsd(float csd) {
try {
getService().setCsd(csd);
@@ -6580,7 +6750,7 @@
* since this can affect the certification of a device with EN50332-3 regulation.
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void forceUseFrameworkMel(boolean useFrameworkMel) {
try {
getService().forceUseFrameworkMel(useFrameworkMel);
@@ -6594,7 +6764,7 @@
* Forces the computation of CSD on all output devices.
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
try {
getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices);
@@ -6608,7 +6778,7 @@
* Returns whether CSD is enabled on this device.
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
public boolean isCsdEnabled() {
try {
return getService().isCsdEnabled();
@@ -7642,7 +7812,7 @@
*
* @return true if successful, otherwise false
*/
- @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
try {
return getService().setEncodedSurroundMode(mode);
@@ -7694,7 +7864,7 @@
* @param enabled the required surround format state, true for enabled, false for disabled
* @return true if successful, otherwise false
*/
- @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
public boolean setSurroundFormatEnabled(
@AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
try {
@@ -7758,7 +7928,7 @@
* Ultrasound playback and capture, false otherwise.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
+ @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND)
public boolean isUltrasoundSupported() {
try {
return getService().isUltrasoundSupported();
@@ -7779,7 +7949,7 @@
* open. False otherwise.
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
+ @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
public boolean isHotwordStreamSupported(boolean lookbackAudio) {
try {
return getService().isHotwordStreamSupported(lookbackAudio);
@@ -7803,7 +7973,7 @@
*/
@SystemApi
@NonNull
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public static List<AudioProductStrategy> getAudioProductStrategies() {
final IAudioService service = getService();
try {
@@ -7823,7 +7993,7 @@
*/
@SystemApi
@NonNull
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public static List<AudioVolumeGroup> getAudioVolumeGroups() {
final IAudioService service = getService();
try {
@@ -8075,7 +8245,7 @@
/** @hide
* TODO: make this a @SystemApi */
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setMultiAudioFocusEnabled(boolean enabled) {
try {
getService().setMultiAudioFocusEnabled(enabled);
@@ -8119,7 +8289,7 @@
* latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
* {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
* telephony application with permission
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+ * {@link Manifest.permission#MODIFY_PHONE_STATE}.
* <p> If the requested devices is not currently available, the request will be rejected and
* the method will return false.
* <p>This API replaces the following deprecated APIs:
@@ -8386,7 +8556,7 @@
*/
@TestApi
@SystemApi
- @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
+ @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
public boolean isPstnCallAudioInterceptable() {
final IAudioService service = getService();
try {
@@ -8487,7 +8657,7 @@
*/
@TestApi
@SystemApi
- @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
+ @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
Objects.requireNonNull(format);
checkCallRedirectionFormat(format, true /* isOutput */);
@@ -8559,7 +8729,7 @@
*/
@TestApi
@SystemApi
- @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
+ @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
Objects.requireNonNull(format);
checkCallRedirectionFormat(format, false /* isOutput */);
@@ -8668,7 +8838,7 @@
* @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void muteAwaitConnection(@NonNull int[] usagesToMute,
@NonNull AudioDeviceAttributes device,
long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
@@ -8698,7 +8868,7 @@
* or because it timed out)
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
try {
return getService().getMutingExpectedDevice();
@@ -8718,7 +8888,7 @@
* {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
throws IllegalStateException {
Objects.requireNonNull(device);
@@ -8797,7 +8967,7 @@
* @param callback the callback to register
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void registerMuteAwaitConnectionCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull MuteAwaitConnectionCallback callback) {
@@ -8821,7 +8991,7 @@
* @param callback the callback to unregister
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void unregisterMuteAwaitConnectionCallback(
@NonNull MuteAwaitConnectionCallback callback) {
synchronized (mMuteAwaitConnectionListenerLock) {
@@ -8843,7 +9013,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void addAssistantServicesUids(@NonNull int[] assistantUids) {
try {
getService().addAssistantServicesUids(assistantUids);
@@ -8860,7 +9030,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
try {
getService().removeAssistantServicesUids(assistantUids);
@@ -8885,7 +9055,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public @NonNull int[] getAssistantServicesUids() {
try {
int[] uids = getService().getAssistantServicesUids();
@@ -8910,7 +9080,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
try {
getService().setActiveAssistantServiceUids(assistantUids);
@@ -8928,7 +9098,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public @NonNull int[] getActiveAssistantServicesUids() {
try {
int[] uids = getService().getActiveAssistantServiceUids();
@@ -9002,7 +9172,7 @@
* @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
* @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
@NonNull AudioDeviceInfo device,
@NonNull AudioMixerAttributes mixerAttributes) {
@@ -9056,7 +9226,7 @@
* @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
* @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
public boolean clearPreferredMixerAttributes(
@NonNull AudioAttributes attributes,
@NonNull AudioDeviceInfo device) {
@@ -9176,7 +9346,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean supportsBluetoothVariableLatency() {
try {
return getService().supportsBluetoothVariableLatency();
@@ -9193,7 +9363,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setBluetoothVariableLatencyEnabled(boolean enabled) {
try {
getService().setBluetoothVariableLatencyEnabled(enabled);
@@ -9207,7 +9377,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean isBluetoothVariableLatencyEnabled() {
try {
return getService().isBluetoothVariableLatencyEnabled();
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5ba7891..3e0356f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -138,18 +138,25 @@
@EnforcePermission("MODIFY_AUDIO_ROUTING")
List<AudioVolumeGroup> getAudioVolumeGroups();
- @EnforcePermission("MODIFY_AUDIO_ROUTING")
- void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags,
- String callingPackage, in String attributionTag);
+ @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"})
+ void setVolumeGroupVolumeIndex(int groupId, int index, int flags, String callingPackage,
+ in String attributionTag);
- @EnforcePermission("MODIFY_AUDIO_ROUTING")
- int getVolumeIndexForAttributes(in AudioAttributes aa);
+ @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"})
+ int getVolumeGroupVolumeIndex(int groupId);
- @EnforcePermission("MODIFY_AUDIO_ROUTING")
- int getMaxVolumeIndexForAttributes(in AudioAttributes aa);
+ @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"})
+ int getVolumeGroupMaxVolumeIndex(int groupId);
- @EnforcePermission("MODIFY_AUDIO_ROUTING")
- int getMinVolumeIndexForAttributes(in AudioAttributes aa);
+ @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"})
+ int getVolumeGroupMinVolumeIndex(int groupId);
+
+ @EnforcePermission("QUERY_AUDIO_STATE")
+ int getLastAudibleVolumeGroupVolume(int groupId);
+
+ boolean isVolumeGroupMuted(int groupId);
+
+ void adjustVolumeGroupVolume(int groupId, int direction, int flags, String callingPackage);
@EnforcePermission("QUERY_AUDIO_STATE")
int getLastAudibleStreamVolume(int streamType);
@@ -405,10 +412,11 @@
oneway void setRttEnabled(in boolean rttEnabled);
- @EnforcePermission("MODIFY_AUDIO_ROUTING")
+ @EnforcePermission(anyOf = {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
void setDeviceVolumeBehavior(in AudioDeviceAttributes device,
in int deviceVolumeBehavior, in String pkgName);
+ @EnforcePermission(anyOf = {"MODIFY_AUDIO_ROUTING", "QUERY_AUDIO_STATE", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
int getDeviceVolumeBehavior(in AudioDeviceAttributes device);
// WARNING: read warning at top of file, new methods that need to be used by native
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index aa7e4df..f739365 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -94,4 +94,5 @@
void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
String sessionId, int volume);
void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId);
+ void showMediaOutputSwitcher(String packageName);
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index a7959c5..24ec227 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -461,6 +461,19 @@
}
/**
+ * Shows the system UI output switcher.
+ */
+ public void showSystemOutputSwitcher() {
+ synchronized (mLock) {
+ try {
+ mMediaRouterService.showMediaOutputSwitcher(mPackageName);
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Sets the {@link RouteListingPreference} of the app associated to this media router.
*
* <p>Use this method to inform the system UI of the routes that you would like to list for
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 0198419..f84eec6 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -233,6 +233,16 @@
/**
* @hide
+ * @return the product strategy ID (which is the generalisation of Car Audio Usage / legacy
+ * routing_strategy linked to {@link AudioAttributes#getUsage()}).
+ */
+ @SystemApi
+ @NonNull public String getName() {
+ return mName;
+ }
+
+ /**
+ * @hide
* @return first {@link AudioAttributes} associated to this product strategy.
*/
@SystemApi
diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS
index e5d0370..01b2cb9 100644
--- a/media/java/android/media/soundtrigger/OWNERS
+++ b/media/java/android/media/soundtrigger/OWNERS
@@ -1,2 +1,2 @@
-ytai@google.com
+atneya@google.com
elaurent@google.com
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 27c2a98..ac920d2 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -1170,6 +1170,11 @@
* in Tuner 2.0 or higher version. Unsupported version will cause no-op. Use {@link
* TunerVersionChecker#getTunerVersion()} to get the version information.
*
+ * <p>Tuning with {@link
+ * android.media.tv.tuner.frontend.IptvFrontendSettings} is only supported
+ * in Tuner 3.0 or higher version. Unsupported version will cause no-op. Use {@link
+ * TunerVersionChecker#getTunerVersion()} to get the version information.
+ *
* @param settings Signal delivery information the frontend uses to
* search and lock the signal.
* @return result status of tune operation.
@@ -1198,6 +1203,12 @@
return RESULT_UNAVAILABLE;
}
}
+ if (mFrontendType == FrontendSettings.TYPE_IPTV) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "Tuner with IPTV Frontend")) {
+ return RESULT_UNAVAILABLE;
+ }
+ }
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, mFrontendLock)) {
mFrontendInfo = null;
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2f45a70..0a1ecee 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -38,7 +38,7 @@
/** @hide */
@IntDef(prefix = "TYPE_",
value = {TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS,
- TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT, TYPE_DTMB})
+ TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT, TYPE_DTMB, TYPE_IPTV})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
@@ -86,7 +86,10 @@
* Digital Terrestrial Multimedia Broadcast standard (DTMB) frontend type.
*/
public static final int TYPE_DTMB = FrontendType.DTMB;
-
+ /**
+ * Internet Protocol (IPTV) frontend type.
+ */
+ public static final int TYPE_IPTV = FrontendType.IPTV;
/** @hide */
@LongDef(prefix = "FEC_",
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 9fbea72..fd677ac 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -23,6 +23,7 @@
import android.annotation.SystemApi;
import android.media.tv.tuner.Lnb;
import android.media.tv.tuner.TunerVersionChecker;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
@@ -57,7 +58,10 @@
FRONTEND_STATUS_TYPE_IS_MISO_ENABLED, FRONTEND_STATUS_TYPE_IS_LINEAR,
FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED, FRONTEND_STATUS_TYPE_ISDBT_MODE,
FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS,
- FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO})
+ FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO,
+ FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL, FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST,
+ FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED, FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS,
+ FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS})
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendStatusType {}
@@ -271,6 +275,36 @@
android.hardware.tv.tuner.FrontendStatusType.DVBT_CELL_IDS;
/**
+ * IPTV content URL.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL =
+ android.hardware.tv.tuner.FrontendStatusType.IPTV_CONTENT_URL;
+
+ /**
+ * IPTV packets lost.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST =
+ android.hardware.tv.tuner.FrontendStatusType.IPTV_PACKETS_LOST;
+
+ /**
+ * IPTV packets received.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED =
+ android.hardware.tv.tuner.FrontendStatusType.IPTV_PACKETS_RECEIVED;
+
+ /**
+ * IPTV worst jitter.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS =
+ android.hardware.tv.tuner.FrontendStatusType.IPTV_WORST_JITTER_MS;
+
+ /**
+ * IPTV average jitter.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS =
+ android.hardware.tv.tuner.FrontendStatusType.IPTV_AVERAGE_JITTER_MS;
+
+ /**
* All PLP information in a frequency band for ATSC-3.0 frontend, which includes both tuned and
* not tuned PLPs for currently watching service.
*/
@@ -519,6 +553,11 @@
private int[] mStreamIds;
private int[] mDvbtCellIds;
private Atsc3PlpInfo[] mAllPlpInfo;
+ private String mIptvContentUrl;
+ private Long mIptvPacketsLost;
+ private Long mIptvPacketsReceived;
+ private Integer mIptvWorstJitterMs;
+ private Integer mIptvAverageJitterMs;
// Constructed and fields set by JNI code.
private FrontendStatus() {
@@ -1144,4 +1183,94 @@
return mUec;
}
}
+
+ /**
+ * Gets the IPTV content URL.
+ *
+ * @return A String URL in the format protocol://ip:port (udp://127.0.0.1:3000).
+ *
+ * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @NonNull
+ public String getIptvContentUrl() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "IptvContentUrl status");
+ if (mIptvContentUrl == null) {
+ throw new IllegalStateException("IptvContentUrl status is empty");
+ }
+ return mIptvContentUrl;
+ }
+
+ /**
+ * Gets the number of packets lost.
+ *
+ * @return A long value representing the number of packets lost in transmission.
+ *
+ * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @IntRange(from = 0)
+ public long getIptvPacketsLost() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "IptvPacketsLost status");
+ if (mIptvPacketsLost == null) {
+ throw new IllegalStateException("IptvPacketsLost status is empty");
+ }
+ return mIptvPacketsLost;
+ }
+
+ /**
+ * Gets the number of packets received.
+ *
+ * @return A long value representing the number of packets received.
+ *
+ * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @IntRange(from = 0)
+ public long getIptvPacketsReceived() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "IptvPacketsReceived status");
+ if (mIptvPacketsReceived == null) {
+ throw new IllegalStateException("IptvPacketsReceived status is empty");
+ }
+ return mIptvPacketsReceived;
+ }
+
+ /**
+ * Gets the worst jitter.
+ *
+ * @return An integer representing worst jitter recorded (in milliseconds).
+ *
+ * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @IntRange(from = 0)
+ public int getIptvWorstJitterMillis() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "IptvWorstJitterMs status");
+ if (mIptvWorstJitterMs == null) {
+ throw new IllegalStateException("IptvWorstJitterMs status is empty");
+ }
+ return mIptvWorstJitterMs;
+ }
+
+ /**
+ * Gets the average jitter.
+ *
+ * @return An integer representing average jitter recorded (in milliseconds).
+ *
+ * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @IntRange(from = 0)
+ public int getIptvAverageJitterMillis() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_3_0, "IptvAverageJitterMs status");
+ if (mIptvAverageJitterMs == null) {
+ throw new IllegalStateException("IptvAverageJitterMs status is empty");
+ }
+ return mIptvAverageJitterMs;
+ }
}
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
new file mode 100644
index 0000000..fb11ea9
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.Size;
+import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendIptvSettingsIgmp;
+import android.hardware.tv.tuner.FrontendIptvSettingsProtocol;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Frontend settings for IPTV.
+ *
+ * @hide
+ */
+@SystemApi
+public class IptvFrontendSettings extends FrontendSettings {
+ /** @hide */
+ @IntDef(prefix = "PROTOCOL_",
+ value = {PROTOCOL_UNDEFINED, PROTOCOL_UDP, PROTOCOL_RTP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Protocol {}
+
+ /**
+ * IP protocol type UNDEFINED.
+ */
+ public static final int PROTOCOL_UNDEFINED = FrontendIptvSettingsProtocol.UNDEFINED;
+
+ /**
+ * IP protocol type UDP (User Datagram Protocol).
+ */
+ public static final int PROTOCOL_UDP = FrontendIptvSettingsProtocol.UDP;
+
+ /**
+ * IP protocol type RTP (Real-time Transport Protocol).
+ */
+ public static final int PROTOCOL_RTP = FrontendIptvSettingsProtocol.RTP;
+
+ /** @hide */
+ @IntDef(prefix = "IGMP_",
+ value = {IGMP_UNDEFINED, IGMP_V1, IGMP_V2, IGMP_V3})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Igmp {}
+
+ /**
+ * IGMP (Internet Group Management Protocol) UNDEFINED.
+ */
+ public static final int IGMP_UNDEFINED = FrontendIptvSettingsIgmp.UNDEFINED;
+
+ /**
+ * IGMP (Internet Group Management Protocol) V1.
+ */
+ public static final int IGMP_V1 = FrontendIptvSettingsIgmp.V1;
+
+ /**
+ * IGMP (Internet Group Management Protocol) V2.
+ */
+ public static final int IGMP_V2 = FrontendIptvSettingsIgmp.V2;
+
+ /**
+ * IGMP (Internet Group Management Protocol) V3.
+ */
+ public static final int IGMP_V3 = FrontendIptvSettingsIgmp.V3;
+
+ private final byte[] mSrcIpAddress;
+ private final byte[] mDstIpAddress;
+ private final int mSrcPort;
+ private final int mDstPort;
+ private final IptvFrontendSettingsFec mFec;
+ private final int mProtocol;
+ private final int mIgmp;
+ private final long mBitrate;
+ private final String mContentUrl;
+
+ public IptvFrontendSettings(@NonNull byte[] srcIpAddress, @NonNull byte[] dstIpAddress,
+ int srcPort, int dstPort, @NonNull IptvFrontendSettingsFec fec, int protocol, int igmp,
+ long bitrate, @NonNull String contentUrl) {
+ super(0);
+ mSrcIpAddress = srcIpAddress;
+ mDstIpAddress = dstIpAddress;
+ mSrcPort = srcPort;
+ mDstPort = dstPort;
+ mFec = fec;
+ mProtocol = protocol;
+ mIgmp = igmp;
+ mBitrate = bitrate;
+ mContentUrl = contentUrl;
+ }
+
+ /**
+ * Gets the source IP address.
+ */
+ @Size(min = 4, max = 16)
+ @NonNull
+ public byte[] getSrcIpAddress() {
+ return mSrcIpAddress;
+ }
+
+ /**
+ * Gets the destination IP address.
+ */
+ @Size(min = 4, max = 16)
+ @NonNull
+ public byte[] getDstIpAddress() {
+ return mDstIpAddress;
+ }
+
+ /**
+ * Gets the source port.
+ */
+ public int getSrcPort() {
+ return mSrcPort;
+ }
+
+ /**
+ * Gets the destination port.
+ */
+ public int getDstPort() {
+ return mDstPort;
+ }
+
+ /**
+ * Gets FEC (Forward Error Correction).
+ */
+ @Nullable
+ public IptvFrontendSettingsFec getFec() {
+ return mFec;
+ }
+
+ /**
+ * Gets the protocol.
+ */
+ @Protocol
+ public int getProtocol() {
+ return mProtocol;
+ }
+
+ /**
+ * Gets the IGMP (Internet Group Management Protocol).
+ */
+ @Igmp
+ public int getIgmp() {
+ return mIgmp;
+ }
+
+ /**
+ * Gets the bitrate.
+ */
+ @IntRange(from = 0)
+ public long getBitrate() {
+ return mBitrate;
+ }
+
+ /**
+ * Gets the contentUrl
+ * contentUrl is a source URL in the format protocol://ip:port containing data
+ */
+ @NonNull
+ public String getContentUrl() {
+ return mContentUrl;
+ }
+
+ /**
+ * Creates a builder for {@link IptvFrontendSettings}.
+ */
+ @NonNull
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link IptvFrontendSettings}.
+ */
+ public static final class Builder {
+ private byte[] mSrcIpAddress = {0, 0, 0, 0};
+ private byte[] mDstIpAddress = {0, 0, 0, 0};
+ private int mSrcPort = 0;
+ private int mDstPort = 0;
+ private IptvFrontendSettingsFec mFec = null;
+ private int mProtocol = FrontendIptvSettingsProtocol.UNDEFINED;
+ private int mIgmp = FrontendIptvSettingsIgmp.UNDEFINED;
+ private long mBitrate = 0;
+ private String mContentUrl = "";
+
+ private Builder() {
+ }
+
+ /**
+ * Sets the source IP address.
+ *
+ * <p>Default value is 0.0.0.0, an invalid IP address.
+ */
+ @NonNull
+ public Builder setSrcIpAddress(@NonNull byte[] srcIpAddress) {
+ mSrcIpAddress = srcIpAddress;
+ return this;
+ }
+
+ /**
+ * Sets the destination IP address.
+ *
+ * <p>Default value is 0.0.0.0, an invalid IP address.
+ */
+ @NonNull
+ public Builder setDstIpAddress(@NonNull byte[] dstIpAddress) {
+ mDstIpAddress = dstIpAddress;
+ return this;
+ }
+
+ /**
+ * Sets the source IP port.
+ *
+ * <p>Default value is 0.
+ */
+ @NonNull
+ public Builder setSrcPort(int srcPort) {
+ mSrcPort = srcPort;
+ return this;
+ }
+
+ /**
+ * Sets the destination IP port.
+ *
+ * <p>Default value is 0.
+ */
+ @NonNull
+ public Builder setDstPort(int dstPort) {
+ mDstPort = dstPort;
+ return this;
+ }
+
+ /**
+ * Sets the FEC (Forward Error Correction).
+ *
+ * <p>Default value is {@code null}.
+ */
+ @NonNull
+ public Builder setFec(@Nullable IptvFrontendSettingsFec fec) {
+ mFec = fec;
+ return this;
+ }
+
+ /**
+ * Sets the protocol.
+ *
+ * <p>Default value is {@link #PROTOCOL_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setProtocol(@Protocol int protocol) {
+ mProtocol = protocol;
+ return this;
+ }
+
+ /**
+ * Sets the IGMP (Internet Group Management Protocol).
+ *
+ * <p>Default value is {@link #IGMP_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setIgmp(@Igmp int igmp) {
+ mIgmp = igmp;
+ return this;
+ }
+
+ /**
+ * Sets the bitrate.
+ *
+ * <p>Default value is 0.
+ */
+ @NonNull
+ public Builder setBitrate(@IntRange(from = 0) long bitrate) {
+ mBitrate = bitrate;
+ return this;
+ }
+
+ /**
+ * Sets the contentUrl.
+ *
+ * <p>Default value is "".
+ */
+ @NonNull
+ public Builder setContentUrl(@NonNull String contentUrl) {
+ mContentUrl = contentUrl;
+ return this;
+ }
+
+ /**
+ * Builds a {@link IptvFrontendSettings} object.
+ */
+ @NonNull
+ public IptvFrontendSettings build() {
+ return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort,
+ mDstPort, mFec, mProtocol, mIgmp, mBitrate, mContentUrl);
+ }
+ }
+
+ @Override
+ public int getType() {
+ return FrontendSettings.TYPE_IPTV;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
new file mode 100644
index 0000000..699d615
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendIptvSettingsFecType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * FEC (Forward Error Correction) for IPTV.
+ *
+ * @hide
+ */
+@SystemApi
+public class IptvFrontendSettingsFec {
+ /** @hide */
+ @IntDef(prefix = "FEC_TYPE_",
+ value = {FEC_TYPE_UNDEFINED, FEC_TYPE_COLUMN, FEC_TYPE_ROW, FEC_TYPE_COLUMN_ROW})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FecType {}
+
+ /**
+ * FEC (Forward Error Correction) type UNDEFINED.
+ */
+ public static final int FEC_TYPE_UNDEFINED = FrontendIptvSettingsFecType.UNDEFINED;
+
+ /**
+ * FEC (Forward Error Correction) type Column.
+ */
+ public static final int FEC_TYPE_COLUMN = FrontendIptvSettingsFecType.COLUMN;
+
+ /**
+ * FEC (Forward Error Correction) type ROW.
+ */
+ public static final int FEC_TYPE_ROW = FrontendIptvSettingsFecType.ROW;
+
+ /**
+ * FEC (Forward Error Correction) type Column Row.
+ */
+ public static final int FEC_TYPE_COLUMN_ROW = FrontendIptvSettingsFecType.COLUMN_ROW;
+
+ private final int mFecType;
+ private final int mFecRowNum;
+ private final int mFecColNum;
+
+ public IptvFrontendSettingsFec(@FecType int fecType, int fecRowNum, int fecColNum) {
+ mFecType = fecType;
+ mFecRowNum = fecRowNum;
+ mFecColNum = fecColNum;
+ }
+
+ /**
+ * Gets the FEC (Forward Error Correction) type.
+ */
+ @FecType
+ public int getFecType() {
+ return mFecType;
+ }
+
+ /**
+ * Get the FEC (Forward Error Correction) row number.
+ */
+ @IntRange(from = 0)
+ public int getFecRowNum() {
+ return mFecRowNum;
+ }
+
+ /**
+ * Gets the FEC (Forward Error Correction) column number.
+ */
+ @IntRange(from = 0)
+ public int getFecColNum() {
+ return mFecColNum;
+ }
+
+ /**
+ * Creates a builder for {@link IptvFrontendSettingsFec}.
+ */
+ @NonNull
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link IptvFrontendSettingsFec}.
+ */
+ public static final class Builder {
+ private int mFecType;
+ private int mFecRowNum;
+ private int mFecColNum;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets the FEC (Forward Error Correction) type
+ */
+ @NonNull
+ public Builder setFecType(@FecType int fecType) {
+ mFecType = fecType;
+ return this;
+ }
+ /**
+ * Sets the FEC (Forward Error Correction) row number.
+ */
+ @NonNull
+ public Builder setFecRowNum(@IntRange(from = 0) int fecRowNum) {
+ mFecRowNum = fecRowNum;
+ return this;
+ }
+ /**
+ * Sets the FEC (Forward Error Correction) column number.
+ */
+ @NonNull
+ public Builder setFecColNum(@IntRange(from = 0) int fecColNum) {
+ mFecColNum = fecColNum;
+ return this;
+ }
+
+ /**
+ * Builds a {@link IptvFrontendSettingsFec} object.
+ */
+ @NonNull
+ public IptvFrontendSettingsFec build() {
+ return new IptvFrontendSettingsFec(mFecType, mFecRowNum, mFecColNum);
+ }
+ }
+}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index a73725b..35ee3ee9 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -490,9 +490,11 @@
}
void MediaEvent::finalize() {
- if (mAvHandleRefCnt == 0 && mFilterClient != nullptr) {
- mFilterClient->releaseAvHandle(
- mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0);
+ if (mAvHandleRefCnt == 0) {
+ if (mFilterClient != nullptr) {
+ mFilterClient->releaseAvHandle(
+ mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0);
+ }
native_handle_close(mAvHandle);
}
}
@@ -2825,6 +2827,52 @@
env->DeleteLocalRef(plpClazz);
break;
}
+ case FrontendStatus::Tag::iptvContentUrl: {
+ jfieldID field = env->GetFieldID(clazz, "mIptvContentUrl", "Ljava/lang/String;");
+ std::string iptvContentUrl = s.get<FrontendStatus::Tag::iptvContentUrl>();
+ jstring iptvContentUrlUtf8 = env->NewStringUTF(iptvContentUrl.c_str());
+ env->SetObjectField(statusObj, field, iptvContentUrlUtf8);
+ env->DeleteLocalRef(iptvContentUrlUtf8);
+ break;
+ }
+ case FrontendStatus::Tag::iptvPacketsLost: {
+ jfieldID field = env->GetFieldID(clazz, "mIptvPacketsLost", "Ljava/lang/Long;");
+ jobject newLongObj =
+ env->NewObject(longClazz, initLong,
+ s.get<FrontendStatus::Tag::iptvPacketsLost>());
+ env->SetObjectField(statusObj, field, newLongObj);
+ env->DeleteLocalRef(newLongObj);
+ break;
+ }
+ case FrontendStatus::Tag::iptvPacketsReceived: {
+ jfieldID field = env->GetFieldID(clazz, "mIptvPacketsReceived", "Ljava/lang/Long;");
+ jobject newLongObj =
+ env->NewObject(longClazz, initLong,
+ s.get<FrontendStatus::Tag::iptvPacketsReceived>());
+ env->SetObjectField(statusObj, field, newLongObj);
+ env->DeleteLocalRef(newLongObj);
+ break;
+ }
+ case FrontendStatus::Tag::iptvWorstJitterMs: {
+ jfieldID field = env->GetFieldID(clazz, "mIptvWorstJitterMs",
+ "Ljava/lang/Integer;");
+ jobject newIntegerObj =
+ env->NewObject(intClazz, initInt,
+ s.get<FrontendStatus::Tag::iptvWorstJitterMs>());
+ env->SetObjectField(statusObj, field, newIntegerObj);
+ env->DeleteLocalRef(newIntegerObj);
+ break;
+ }
+ case FrontendStatus::Tag::iptvAverageJitterMs: {
+ jfieldID field = env->GetFieldID(clazz, "mIptvAverageJitterMs",
+ "Ljava/lang/Integer;");
+ jobject newIntegerObj =
+ env->NewObject(intClazz, initInt,
+ s.get<FrontendStatus::Tag::iptvAverageJitterMs>());
+ env->SetObjectField(statusObj, field, newIntegerObj);
+ env->DeleteLocalRef(newIntegerObj);
+ break;
+ }
}
}
return statusObj;
diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml
index 0e77826..13ae4da 100644
--- a/packages/CarrierDefaultApp/res/values-af/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-af/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Gaan in elk geval deur blaaier voort"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestasiehupstoot"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Verbeter jou 5G-ervaring"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s beveel aan dat jy ’n werkverrigtinghupstootpakket koop. Tik om deur %2$s te koop."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nie nou nie"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Bestuur"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Koop ’n prestasiehupstoot."</string>
diff --git a/packages/CarrierDefaultApp/res/values-am/strings.xml b/packages/CarrierDefaultApp/res/values-am/strings.xml
index 8ab8fbbb..e1f91ce 100644
--- a/packages/CarrierDefaultApp/res/values-am/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-am/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"የአፈጻጸም ጭማሪ"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"የእርስዎን የ5ጂ ተሞክሮ ያሻሽሉ"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s የአፈጻጸም መጨመሪያ ዕቅድ መግዛትን ይመክራል። በ%2$s ለመግዛት መታ ያድርጉ።"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"አሁን አይደለም"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"አስተዳድር"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"የአፈጻጸም ጭማሪ ይግዙ።"</string>
diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml
index d8ee5b96..f64fcb6 100644
--- a/packages/CarrierDefaultApp/res/values-az/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-az/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Hər bir halda brazuer ilə davam edin"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performans artırması"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G təcrübənizi təkmilləşdirin"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s performans artırma planı almağı tövsiyə edir. %2$s ilə almaq üçün toxunun."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"İndi yox"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"İdarə edin"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Performans artırması alın."</string>
diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
index f4adf53..5533bfd 100644
--- a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko pregledača"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje učinka"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte 5G doživljaj"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupovinu paketa za poboljšanje performansi. Dodirnite da biste kupili preko %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljaj"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje učinka."</string>
diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml
index 952a497..0053cda 100644
--- a/packages/CarrierDefaultApp/res/values-be/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-be/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Усё роўна працягнуць праз браўзер"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Павышэнне прадукцыйнасці"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Пашырце магчымасці 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s рэкамендуе купіць план павышэння прадукцыйнасці. Націсніце, каб купіць праз %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не цяпер"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Кіраваць"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Аплаціце павышэнне прадукцыйнасці."</string>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index 052713b..7be8e2b 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pojačavanje performansi"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte iskustvo s 5G mrežom"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupovinu paketa za poboljšanje performansi. Dodirnite da kupite koristeći %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite pojačavanje performansi."</string>
diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml
index d638272..8a09421 100644
--- a/packages/CarrierDefaultApp/res/values-cs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Přihlašovací stránka například nemusí patřit zobrazované organizaci."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Přesto pokračovat prostřednictvím prohlížeče"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zvýšení výkonu"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Získejte rychlejší připojení 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s doporučuje zakoupit zvýšení výkonu. Klepnutím ho zakoupíte přes operátora %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Teď ne"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Spravovat"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupte si zvýšení výkonu."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
index de3baad..720dbc7 100644
--- a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
index 07340fb..87978ac 100644
--- a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
index de3baad..720dbc7 100644
--- a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
index de3baad..720dbc7 100644
--- a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
index f42fdb7..7324a5b 100644
--- a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
index 23836ef..fedf1ac 100644
--- a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos desde el navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de rendimiento"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Mejora tu experiencia de 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomienda que compres un plan de aumento de rendimiento. Presiona para comprar mediante %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ahora no"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Compra un aumento de rendimiento."</string>
diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml
index da4f94f..af09d13 100644
--- a/packages/CarrierDefaultApp/res/values-gu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ બતાવવામાં આવેલી સંસ્થાનું ન પણ હોય."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"તો પણ બ્રાઉઝર મારફતે ચાલુ રાખો"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"પર્ફોર્મન્સ બૂસ્ટ"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"તમારા 5G અનુભવને બહેતર બનાવો"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s પર્ફોર્મન્સ બૂસ્ટ પ્લાન ખરીદવાનો સુઝાવ આપે છે. %2$s મારફતે ખરીદવા માટે ટૅપ કરો."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"હમણાં નહીં"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"મેનેજ કરો"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"પર્ફોર્મન્સ બૂસ્ટ ખરીદો."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml
index 6b12df7..e51b1a9 100644
--- a/packages/CarrierDefaultApp/res/values-hi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरण के लिए, हो सकता है कि लॉगिन पेज दिखाए गए संगठन का ना हो."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ब्राउज़र के ज़रिए किसी भी तरह जारी रखें"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"परफ़ॉर्मेंस बूस्ट"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G का बेहतर अनुभव पाएं"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s, परफ़ॉर्मेंस को बेहतर बनाने वाले प्लान को खरीदने का सुझाव देता है. %2$s से प्लान खरीदने के लिए टैप करें."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अभी नहीं"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"मैनेज करें"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"कोई परफ़ॉर्मेंस बूस्ट खरीदें."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml
index 96d8c3c..5a22ad5 100644
--- a/packages/CarrierDefaultApp/res/values-hr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi putem preglednika"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje izvedbe"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte svoj 5G doživljaj"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupnju paketa za poboljšanje izvedbe. Dodirnite da biste kupili putem usluge %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sad"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje izvedbe."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml
index 63bb75c..49fbece 100644
--- a/packages/CarrierDefaultApp/res/values-hy/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Շարունակել դիտարկիչի միջոցով"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Արտադրողականության բարձրացում"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Բարելավեք 5G-ի օգտագործման ձեր փորձառությունը"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s օպերատորը խորհուրդ է տալիս ձեռք բերել արդյունավետությունը բարձրացնող սակագնային պլան։ Հպեք՝ %2$s-ի միջոցով գնելու համար։"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ոչ հիմա"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Կառավարել"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Բարձրացրեք ցանցի արտադրողականությունը վճարի դիմաց։"</string>
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
index 8dc073c..c7229ba 100644
--- a/packages/CarrierDefaultApp/res/values-iw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"המשך בכל זאת באמצעות דפדפן"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"שיפור ביצועים"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"שיפור חווית השימוש ב-5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"יש המלצה של %1$s לקנות תוכנית לשיפור הביצועים. אפשר להקיש כדי לקנות דרך %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"לא עכשיו"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ניהול"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"רכישת שיפור ביצועים."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml
index 01aa0d7..2fd86c8 100644
--- a/packages/CarrierDefaultApp/res/values-ja/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ブラウザから続行"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"パフォーマンス ブースト"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G のエクスペリエンスを改善"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s さんがパフォーマンス ブースト プランの購入をおすすめしています。%2$sまでにタップして購入しましょう。"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"後で"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"パフォーマンス ブーストを購入してください。"</string>
diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml
index 6640254..76f7273 100644
--- a/packages/CarrierDefaultApp/res/values-ka/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"მაინც ბრაუზერში გაგრძელება"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ეფექტურობის გაძლიერება"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"გააუმჯობესეთ თქვენი 5G გამოცდილება"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s-ის მიერ რეკომენდებულია ეფექტურობის გაძლიერების გეგმის შეძენა. შეეხეთ %2$s-ის დახმარებით შესაძენად."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ახლა არა"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"მართვა"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ეფექტურობის გაძლიერების შეძენა."</string>
diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml
index b3ce678..c97d6f0 100644
--- a/packages/CarrierDefaultApp/res/values-kn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿಲ್ಲದಿರಬಹುದು."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ಪರವಾಗಿಲ್ಲ, ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"ನಿಮ್ಮ 5G ಅನುಭವವನ್ನು ಸುಧಾರಿಸಿ"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಹೆಚ್ಚಿಸುವ ಪ್ಲಾನ್ ಅನ್ನು ಖರೀದಿಸಲು %1$s ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ. %2$s ಮೂಲಕ ಖರೀದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ಈಗ ಬೇಡ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ನಿರ್ವಹಿಸಿ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್ ಅನ್ನು ಖರೀದಿಸಿ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml
index 3a59d1a..395627d 100644
--- a/packages/CarrierDefaultApp/res/values-ko/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"브라우저를 통해 계속하기"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"성능 향상"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G 사용 환경 개선"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s에서 성능 향상 계획 구매를 추천합니다. %2$s을(를) 통해 구매하려면 탭하세요."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"나중에"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"관리"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"성능 향상 구매"</string>
diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml
index 368e706..b3970e3 100644
--- a/packages/CarrierDefaultApp/res/values-ky/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Иштин майнаптуулугун жогорулатуу"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G менен оңой иштеңиз"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s майнаптуулугун жогорулата турган тарифтик планды сатып алууну сунуштайт. %2$s аркылуу сатып алуу үчүн таптаңыз."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Азыр эмес"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Тескөө"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Иштин майнаптуулугун жогорулатууну сатып алыңыз."</string>
diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml
index 722a8c5..70d8888 100644
--- a/packages/CarrierDefaultApp/res/values-lo/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ຕົວຢ່າງ, ໜ້າເຂົ້າສູ່ລະບົບອາດຈະບໍ່ແມ່ນຂອງອົງກອນທີ່ປາກົດ."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ດຳເນີນການຕໍ່ຜ່ານໂປຣແກຣມທ່ອງເວັບ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ເລັ່ງປະສິດທິພາບ"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"ປັບປຸງປະສົບການ 5G ຂອງທ່ານ"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ແນະນຳໃຫ້ຊື້ແຜນການເລັ່ງປະສິດທິພາບ. ແຕະເພື່ອຊື້ຜ່ານ %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ບໍ່ຟ້າວເທື່ອ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ຈັດການ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ຊື້ການເລັ່ງປະສິດທິພາບ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml
index e8817ef..8068416 100644
--- a/packages/CarrierDefaultApp/res/values-lt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vis tiek tęsti naudojant naršyklę"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Našumo pagerinimas"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Pagerinkite 5G ryšį"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"„%1$s“ rekomenduoja įsigyti našumo pagerinimo planą. Palieskite, kad įsigytumėte naudodamiesi „%2$s“ paslaugomis."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne dabar"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Tvarkyti"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Įsigykite našumo pagerinimo paslaugą."</string>
diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml
index a110920..425edfc 100644
--- a/packages/CarrierDefaultApp/res/values-mk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страницата за најавување може да не припаѓа на прикажаната организација."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Сепак продолжи преку прелистувач"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Засилување на изведбата"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Подобрете го вашето доживување со 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s препорачува да купите пакет за засилување на изведбата. Допрете за да купите преку %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сега"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управувајте"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Купете засилување на изведбата."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml
index 0757149..f258411 100644
--- a/packages/CarrierDefaultApp/res/values-ml/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"പ്രകടന ബൂസ്റ്റ്"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"നിങ്ങളുടെ 5G അനുഭവം മെച്ചപ്പെടുത്തുക"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"പ്രകടന ബൂസ്റ്റ് പ്ലാൻ വാങ്ങാൻ %1$s നിർദ്ദേശിക്കുന്നു. %2$s വഴി വാങ്ങാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ഇപ്പോൾ വേണ്ട"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"മാനേജ് ചെയ്യുക"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"പ്രകടന ബൂസ്റ്റ് വാങ്ങൂ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml
index da7f90c..12e1719 100644
--- a/packages/CarrierDefaultApp/res/values-mn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Жишээлбэл нэвтрэх хуудас нь харагдаж буй байгууллагынх биш байж болно."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ямар ч тохиолдолд хөтчөөр үргэлжлүүлэх"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Гүйцэтгэлийн идэвхжүүлэлт"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G-н хэрэглээгээ сайжруулах"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s гүйцэтгэл нэмэгдүүлэх багцыг худалдаж авахыг зөвлөж байна. %2$s-р дамжуулан худалдан авах бол товшино уу."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Одоо биш"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Удирдах"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Гүйцэтгэлийн идэвхжүүлэлтийг худалдаж аваарай."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml
index 6134874..85651f4 100644
--- a/packages/CarrierDefaultApp/res/values-ms/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Teruskan juga melalui penyemak imbas"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Peningkatan prestasi"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Tingkatkan pengalaman 5G anda"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s mengesyorkan pembelian pelan peningkatan prestasi. Ketik untuk membeli melalui %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Bukan sekarang"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Urus"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Beli perangsang prestasi."</string>
diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml
index 1386b292..34c54b9 100644
--- a/packages/CarrierDefaultApp/res/values-my/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-my/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ဥပမာ− ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှုမရှိခြင်း ဖြစ်နိုင်ပါသည်။"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"မည်သို့ပင်ဖြစ်စေ ဘရောက်ဇာမှတစ်ဆင့် ရှေ့ဆက်ရန်"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ်"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G အသုံးပြုမှု ပိုမိုကောင်းမွန်စေခြင်း"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s သည် စွမ်းဆောင်ရည်မြှင့်တင်သော အစီအစဉ်ဝယ်ရန် အကြံပြုပါသည်။ %2$s မှတစ်ဆင့် ဝယ်ရန် တို့ပါ။"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ယခုမလုပ်ပါ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"စီမံရန်"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ် ဝယ်ယူရန်။"</string>
diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml
index a283f01..b30e3d9 100644
--- a/packages/CarrierDefaultApp/res/values-nb/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Det er for eksempel mulig at påloggingssiden ikke tilhører organisasjonen som vises."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Fortsett likevel via nettleseren"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Bedre ytelse"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Få en bedre 5G-opplevelse"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s anbefaler at du kjøper et abonnement for bedre ytelse. Trykk for å kjøpe via %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ikke nå"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrer"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kjøp bedre ytelse."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml
index 527a4ce..4dccdb9 100644
--- a/packages/CarrierDefaultApp/res/values-ne/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"पर्फर्मेन्स बुस्ट"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G प्रयोग गर्दा अझ राम्रो सुविधा पाउनुहोस्"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ले पर्फर्मेन्स बुस्ट योजना खरिद गर्न सिफारिस गर्छ। %2$s मार्फत खरिद गर्न ट्याप गर्नुहोस्।"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अहिले होइन"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"व्यवस्थापन गर्नुहोस्"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"पर्फर्मेन्स बुस्ट किन्नुहोस्।"</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
index a03c7c2..4a144be 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore sua experiência 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda a compra de um plano para aumento de desempenho. Toque para comprar em %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
index 08148f1..56e0c2d 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim através do navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento do desempenho"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore a sua experiência 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda comprar um plano de melhoria do desempenho. Toque para comprar através do %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerir"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Compre um aumento do desempenho."</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml
index a03c7c2..4a144be 100644
--- a/packages/CarrierDefaultApp/res/values-pt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore sua experiência 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda a compra de um plano para aumento de desempenho. Toque para comprar em %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml
index 6c59687..f861137 100644
--- a/packages/CarrierDefaultApp/res/values-ro/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuă oricum prin browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performanță"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Îmbunătățește-ți experiența cu tehnologia 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomandă cumpărarea unui plan pentru îmbunătățirea performanței. Atinge pentru a cumpăra de la %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nu acum"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestionează"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Achiziționează un boost de performanță."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml
index a7cf01d..f0bff17 100644
--- a/packages/CarrierDefaultApp/res/values-ru/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Например, страница входа в аккаунт может быть фиктивной."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Продолжить в браузере"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Повышение производительности"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Сделайте работу с 5G удобнее"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"\"%1$s\" рекомендует купить тарифный план, повышающий производительность. Чтобы приобрести тариф у оператора \"%2$s\", коснитесь экрана."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сейчас"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Настроить"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Повысьте производительность сети за плату."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml
index 8c72ac3..3c1fd3e 100644
--- a/packages/CarrierDefaultApp/res/values-sl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vseeno nadaljuj v brskalniku"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ojačevalnik zmogljivosti"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Izboljšajte izkušnjo omrežja 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s priporoča nakup paketa ojačevalnika zmogljivosti. Dotaknite se za nakup prek »%2$s«."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne zdaj"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljanje"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite ojačevalnik zmogljivosti."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml
index 990b531..d28bacc 100644
--- a/packages/CarrierDefaultApp/res/values-sr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страница за пријављивање можда не припада приказаној организацији."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ипак настави преко прегледача"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Побољшање учинка"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Побољшајте 5G доживљај"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s препоручује куповину пакета за побољшање перформанси. Додирните да бисте купили преко %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сада"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управљај"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Купите побољшање учинка."</string>
diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml
index d1c3086..f31291e 100644
--- a/packages/CarrierDefaultApp/res/values-te/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-te/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించండి"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"పనితీరు బూస్ట్"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"మీ 5G అనుభవాన్ని మెరుగుపరుచుకోండి"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"పనితీరును బూస్ట్ చేసే ప్లాన్ను కొనుగోలు చేయమని %1$s సిఫార్సు చేస్తున్నారు. %2$s ద్వారా కొనుగోలు చేయడానికి ట్యాప్ చేయండి."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ఇప్పుడు కాదు"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"మేనేజ్ చేయండి"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"పనితీరు బూస్ట్ను కొనుగోలు చేయండి."</string>
diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml
index 1b5749c..f20346e 100644
--- a/packages/CarrierDefaultApp/res/values-th/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-th/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ดำเนินการต่อผ่านเบราว์เซอร์"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"การเพิ่มประสิทธิภาพ"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"ปรับปรุงประสบการณ์การใช้งาน 5G ของคุณ"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s แนะนำให้ซื้อแพ็กเกจเพิ่มประสิทธิภาพ แตะเพื่อซื้อผ่าน %2$s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ไว้ทีหลัง"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"จัดการ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ซื้อการเพิ่มประสิทธิภาพ"</string>
diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml
index 6543c68..9e8029a 100644
--- a/packages/CarrierDefaultApp/res/values-tl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Halimbawa, maaaring hindi pag-aari ng ipinapakitang organisasyon ang page ng login."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Magpatuloy pa rin sa pamamagitan ng browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pag-boost ng performance"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Pagandahin ang iyong karanasan sa 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"Inirerekomenda ng %1$s na bumili ng plan sa performance boost. I-tap para bumili sa pamamagitan ng %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Huwag muna"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Pamahalaan"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Bumili ng pang-boost ng performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index e878156..681998b 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"پرفارمینس بوسٹ"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"اپنے 5G تجربے کو بہتر بنائیں"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ایک پرفارمنس بوسٹ پلان کی تجویز کرتا ہے۔ %2$s استعمال کر کے خریدنے کے لیے تھپتھپائیں۔"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ابھی نہیں"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"نظم کریں"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"پرفارمینس بوسٹ خریدیں۔"</string>
diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml
index 9c77538..47006f6 100644
--- a/packages/CarrierDefaultApp/res/values-uz/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Brauzerda davom ettirish"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Unumdorlikni kuchaytirish"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"5G bilan ishlashni qulaylashtiring"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s unumdorlikni oshiradigan tarif rejasini xarid qilishni tavsiya etadi. %2$s orqali xarid qilish uchun bosing."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hozir emas"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Boshqarish"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Unumdorlikni kuchaytirish xizmatini xarid qiling."</string>
diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml
index 16a740e..968b6e1 100644
--- a/packages/CarrierDefaultApp/res/values-vi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Ví dụ: trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vẫn tiếp tục qua trình duyệt"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Tăng hiệu suất"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Cải thiện trải nghiệm sử dụng 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s đề xuất bạn mua gói tăng cường hiệu suất. Nhấn để mua thông qua %2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Để sau"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Quản lý"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Mua gói tăng hiệu suất."</string>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
index d5ddc1a..53b71ab 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登入頁面可能並不屬於所顯示的機構。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升服務"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"改善 5G 體驗"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"「%1$s」建議購買效能提升方案,輕觸即可透過「%2$s」購買。"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升服務。"</string>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
index d8a6262..332ab9c 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升方案"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"改善 5G 體驗"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"「%1$s」建議購買效能提升方案,輕觸即可透過「%2$s」購買。"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升方案。"</string>
diff --git a/packages/CarrierDefaultApp/res/values-zu/strings.xml b/packages/CarrierDefaultApp/res/values-zu/strings.xml
index 5edadd6..ae84695 100644
--- a/packages/CarrierDefaultApp/res/values-zu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zu/strings.xml
@@ -15,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Qhubeka noma kunjalo ngesiphequluli"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"I-boost yokusebenza"</string>
- <!-- no translation found for performance_boost_notification_title (946857427149305992) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (362407668982648351) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="946857427149305992">"Thuthukisa umuzwa wakho we-5G"</string>
+ <string name="performance_boost_notification_detail" msgid="362407668982648351">"I-%1$s incoma ukuthenga uhlelo lokuthuthukisa ukusebenza. Thepha ukuze uthenge nge-%2$s."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hhayi manje"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Phatha"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Thenga i-boost yokusebenza."</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 6ebe205..655b843 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -43,8 +43,7 @@
<string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
<string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Veita forritum í <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> sömu heimildir og í <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <!-- no translation found for permission_sync_summary (765497944331294275) -->
- <skip />
+ <string name="permission_sync_summary" msgid="765497944331294275">"Þetta getur átt við um <strong>hljóðnema</strong>, <strong>myndavél</strong>, <strong>aðgang að staðsetningu</strong> og aðrar heimildir fyrir viðkvæmu efni í <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>. <br/><br/>Þú getur breytt þessum heimildum hvenær sem er í stillingunum í <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>."</string>
<string name="vendor_icon_description" msgid="4445875290032225965">"Tákn forrits"</string>
<string name="vendor_header_button_description" msgid="6566660389500630608">"Hnappur fyrir upplýsingar"</string>
<string name="permission_phone" msgid="2661081078692784919">"Sími"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index c9106c3..97db70a 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot je <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
<string name="summary_watch" msgid="4085794790142204006">"De app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot rechten voor Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
<string name="summary_watch_single_device" msgid="1523091550243476756">"De app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> heeft toestemming om interactie te hebben met de volgende rechten:"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 7ab2992..6f19a84 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -57,13 +57,13 @@
<string name="permission_notification" msgid="693762568127741203">"通知"</string>
<string name="permission_app_streaming" msgid="6009695219091526422">"應用程式"</string>
<string name="permission_nearby_device_streaming" msgid="5868108148065023161">"附近的裝置串流"</string>
- <string name="permission_phone_summary" msgid="6684396967861278044">"可撥打及管理通話"</string>
- <string name="permission_call_logs_summary" msgid="6186103394658755022">"可讀取及寫入通話記錄"</string>
- <string name="permission_sms_summary" msgid="3508442683678912017">"可傳送及查看簡訊"</string>
- <string name="permission_contacts_summary" msgid="675861979475628708">"可存取聯絡人"</string>
+ <string name="permission_phone_summary" msgid="6684396967861278044">"可撥打電話和管理通話"</string>
+ <string name="permission_call_logs_summary" msgid="6186103394658755022">"可讀取及寫入手機通話記錄"</string>
+ <string name="permission_sms_summary" msgid="3508442683678912017">"可傳送及查看短訊"</string>
+ <string name="permission_contacts_summary" msgid="675861979475628708">"可存取通訊錄"</string>
<string name="permission_calendar_summary" msgid="6460000922511766226">"可存取日曆"</string>
<string name="permission_microphone_summary" msgid="4241354865859396558">"可使用麥克風錄音"</string>
- <string name="permission_nearby_devices_summary" msgid="931940524460876655">"可尋找、連線及判斷鄰近裝置的相對位置"</string>
+ <string name="permission_nearby_devices_summary" msgid="931940524460876655">"可尋找、連接及判斷附近裝置的相對位置"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
<string name="permission_app_streaming_summary" msgid="606923325679670624">"串流播放手機應用程式內容"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 6d225c3..723f21c 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Kanselleer"</string>
<string name="string_continue" msgid="1346732695941131882">"Gaan voort"</string>
<string name="string_more_options" msgid="7990658711962795124">"Meer opsies"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Veiliger met wagwoordsleutels"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Met wagwoordsleutels hoef jy nie komplekse wagwoorde te skep of te onthou nie"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Wagwoordsleutels is geënkripteerde digitale sleutels wat jy met jou vingerafdruk, gesig of skermslot skep"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Hulle word in ’n wagwoordbestuurder gestoor sodat jy op ander toestelle kan aanmeld"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Kies waar om jou <xliff:g id="CREATETYPES">%1$s</xliff:g> te stoor"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Kies ’n wagwoordbestuurder om jou inligting te stoor en volgende keer vinniger aan te meld"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Skep wagwoordsleutel vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 8c52cf3..3d482f9 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"ይቅር"</string>
<string name="string_continue" msgid="1346732695941131882">"ቀጥል"</string>
<string name="string_more_options" msgid="7990658711962795124">"ተጨማሪ አማራጮች"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"በይለፍ ቃል ይበልጥ ደህንነቱ የተጠበቀ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"በይለፍ ቁልፎች ውስብስብ የይለፍ ቁልፎችን መፍጠር ወይም ማስታወስ አያስፈልግዎትም"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"የይለፍ ቁልፎች የእርስዎን የጣት አሻራ፣ መልክ ወይም የማያ ገጽ መቆለፊያ በመጠቀም የሚፈጥሯቸው የተመሰጠሩ ዲጂታል ቆልፎች ናቸው"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"በሌሎች መሣሪያዎች ላይ መግባት እንዲችሉ በሚስጥር ቁልፍ አስተዳዳሪ ላይ ይቀመጣሉ"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"የእርስዎን <xliff:g id="CREATETYPES">%1$s</xliff:g> የት እንደሚያስቀምጡ ይምረጡ"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"መረጃዎን ለማስቀመጥ እና በቀጣይ ጊዜ በፍጥነት በመለያ ለመግባት የሚስጥር ቁልፍ አስተዳዳሪን ይምረጡ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የይለፍ ቁልፍ ይፈጠር?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የይለፍ ቃል ይቀመጥ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የመግቢያ መረጃ ይቀመጥ?"</string>
<string name="passkey" msgid="632353688396759522">"የይለፍ ቁልፍ"</string>
<string name="password" msgid="6738570945182936667">"የይለፍ ቃል"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"የይለፍ ቁልፎች"</string>
+ <string name="passwords" msgid="5419394230391253816">"የይለፍ ቃላት"</string>
<string name="sign_ins" msgid="4710739369149469208">"መግቢያዎች"</string>
<string name="sign_in_info" msgid="2627704710674232328">"የመግቢያ መረጃ"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>ን አስቀምጥ ወደ"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"በሌላ መሣሪያ ውስጥ የይለፍ ቁልፍ ይፈጠር?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ለሁሉም መግቢያዎችዎ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ን ይጠቀሙ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"ይህ የሚስጥር ቁልፍ አስተዳዳሪ እርስዎን በቀላሉ በመለያ እንዲገቡ ለማገዝ የእርስዎን የይለፍ ቃላት እና የይለፍ ቁልፎችን ያከማቻል"</string>
<string name="set_as_default" msgid="4415328591568654603">"እንደ ነባሪ ያዋቅሩ"</string>
<string name="use_once" msgid="9027366575315399714">"አንዴ ይጠቀሙ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> የይለፍ ቃሎች • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> የይለፍ ቁልፎች"</string>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index 6b90817..47e41a7 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"إلغاء"</string>
<string name="string_continue" msgid="1346732695941131882">"متابعة"</string>
<string name="string_more_options" msgid="7990658711962795124">"خيارات إضافية"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"توفير المزيد من الأمان باستخدام مفاتيح المرور"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"باستخدام مفاتيح المرور، لا حاجة لإنشاء كلمات مرور معقدة أو تذكّرها."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"مفاتيح المرور هي مفاتيح رقمية مشفّرة يمكنك إنشاؤها باستخدام بصمة الإصبع أو التعرّف على الوجه أو قفل الشاشة."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"يتم حفظها في مدير كلمات مرور، حتى تتمكن من تسجيل الدخول على أجهزة أخرى."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"اختَر الموقع الذي تريد حفظ <xliff:g id="CREATETYPES">%1$s</xliff:g> فيه"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"اختَر مدير كلمات مرور لحفظ معلوماتك وتسجيل الدخول بشكل أسرع في المرة القادمة."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"إنشاء مفتاح مرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"هل تريد حفظ كلمة المرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"هل تريد حفظ معلومات تسجيل الدخول لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string>
<string name="passkey" msgid="632353688396759522">"مفتاح مرور"</string>
<string name="password" msgid="6738570945182936667">"كلمة المرور"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"مفاتيح المرور"</string>
+ <string name="passwords" msgid="5419394230391253816">"كلمات المرور"</string>
<string name="sign_ins" msgid="4710739369149469208">"عمليات تسجيل الدخول"</string>
<string name="sign_in_info" msgid="2627704710674232328">"معلومات تسجيل الدخول"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"حفظ <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> في"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"هل تريد إنشاء مفتاح المرور في خدمة أخرى؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"هل تريد استخدام \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" لكل عمليات تسجيل الدخول؟"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"سيخزِّن مدير كلمات المرور هذا كلمات المرور ومفاتيح المرور لمساعدتك في تسجيل الدخول بسهولة."</string>
<string name="set_as_default" msgid="4415328591568654603">"ضبط الخيار كتلقائي"</string>
<string name="use_once" msgid="9027366575315399714">"الاستخدام مرة واحدة"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> كلمة مرور • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> مفتاح مرور"</string>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index 3a92b68..2cea9c8 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"বাতিল কৰক"</string>
<string name="string_continue" msgid="1346732695941131882">"অব্যাহত ৰাখক"</string>
<string name="string_more_options" msgid="7990658711962795124">"অধিক বিকল্প"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"পাছকীৰ জৰিয়তে অধিক সুৰক্ষিত"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"পাছকী ব্যৱহাৰ কৰিলে আপুনি জটিল পাছৱৰ্ড সৃষ্টি কৰিব অথবা মনত ৰাখিব নালাগে"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"পাছকীসমূহ হৈছে আপুনি আপোনাৰ ফিংগাৰপ্ৰিণ্ট, মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰি সৃষ্টি কৰা এনক্ৰিপ্ট কৰা ডিজিটেল চাবি"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"সেইসমূহ এটা পাছৱৰ্ড পৰিচালকত ছেভ কৰা হয়, যাতে আপুনি অন্য ডিভাইচসমূহত ছাইন ইন কৰিব পাৰে"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"আপোনাৰ <xliff:g id="CREATETYPES">%1$s</xliff:g> ক’ত ছেভ কৰিব লাগে সেয়া বাছনি কৰক"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"আপোনাৰ তথ্য ছেভ কৰি পৰৱৰ্তী সময়ত দ্ৰুতভাৱে ছাইন ইন কৰিবলৈ এটা পাছৱৰ্ড পৰিচালক বাছনি কৰক"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে পাছকী সৃষ্টি কৰিবনে?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে পাছৱৰ্ড ছেভ কৰিবনে?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে ছাইন ইনৰ তথ্য ছেভ কৰিবনে?"</string>
<string name="passkey" msgid="632353688396759522">"পাছকী"</string>
<string name="password" msgid="6738570945182936667">"পাছৱৰ্ড"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"পাছকী"</string>
+ <string name="passwords" msgid="5419394230391253816">"পাছৱৰ্ড"</string>
<string name="sign_ins" msgid="4710739369149469208">"ছাইন-ইন"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ছাইন ইনৰ তথ্য"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ইয়াত ছেভ কৰক"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"অন্য এটা ডিভাইচত পাছকী সৃষ্টি কৰিবনে?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"আপোনাৰ আটাইবোৰ ছাইন ইনৰ বাবে <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবনে?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"আপোনাক সহজে ছাইন ইন কৰাত সহায় কৰিবলৈ এই পাছৱৰ্ড পৰিচালকটোৱে আপোনাৰ পাছৱৰ্ড আৰু পাছকী ষ্ট’ৰ কৰিব"</string>
<string name="set_as_default" msgid="4415328591568654603">"ডিফ’ল্ট হিচাপে ছেট কৰক"</string>
<string name="use_once" msgid="9027366575315399714">"এবাৰ ব্যৱহাৰ কৰক"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> টা পাছৱৰ্ড • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> টা পাছকী"</string>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index d7f3025..a987b66 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Ləğv edin"</string>
<string name="string_continue" msgid="1346732695941131882">"Davam edin"</string>
<string name="string_more_options" msgid="7990658711962795124">"Digər seçimlər"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Giriş açarları ilə daha təhlükəsiz"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Giriş açarları ilə mürəkkəb parollar yaratmağa və ya yadda saxlamağa ehtiyac yoxdur"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Giriş açarları barmaq izi, üz və ya ekran kilidindən istifadə edərək yaratdığınız şifrələnmiş rəqəmsal açarlardır"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Onlar parol menecerində saxlanılır ki, digər cihazlarda daxil ola biləsiniz"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> elementinin saxlanacağı yeri seçin"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Məlumatlarınızı yadda saxlamaq və növbəti dəfə daha sürətli daxil olmaq üçün parol meneceri seçin"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş açarı yaradılsın?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün parol yadda saxlanılsın?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş məlumatları yadda saxlansın?"</string>
<string name="passkey" msgid="632353688396759522">"giriş açarı"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"giriş açarları"</string>
+ <string name="passwords" msgid="5419394230391253816">"parollar"</string>
<string name="sign_ins" msgid="4710739369149469208">"girişlər"</string>
<string name="sign_in_info" msgid="2627704710674232328">"Giriş məlumatları"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> burada yadda saxlansın:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Başqa cihazda giriş açarı yaradılsın?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Bütün girişlər üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> istifadə edilsin?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Bu parol meneceri asanlıqla daxil olmanıza kömək etmək üçün parollarınızı və giriş açarlarınızı saxlayacaq"</string>
<string name="set_as_default" msgid="4415328591568654603">"Defolt olaraq seçin"</string>
<string name="use_once" msgid="9027366575315399714">"Bir dəfə istifadə edin"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parol • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> giriş açarı"</string>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index 6e8ec71..5a52190 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Otkaži"</string>
<string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
<string name="string_more_options" msgid="7990658711962795124">"Još opcija"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Bezbednije uz pristupne kodove"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Uz pristupne kodove nema potrebe da pravite ili pamtite složene lozinke"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Pristupni kodovi su šifrovani digitalni kodovi koje pravite pomoću otiska prsta, lica ili zaključavanja ekrana"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Čuvaju se u menadžeru lozinki da biste mogli da se prijavljujete na drugim uređajima"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gde ćete sačuvati stavke <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Izaberite menadžera lozinki da biste sačuvali podatke i brže se prijavili sledeći put"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite da napravite pristupni kôd za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Želite da sačuvate lozinku za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Želite da sačuvate podatke za prijavljivanje za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"pristupni kodovi"</string>
+ <string name="passwords" msgid="5419394230391253816">"lozinke"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijavljivanja"</string>
<string name="sign_in_info" msgid="2627704710674232328">"podaci za prijavljivanje"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Sačuvajte stavku<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> u"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Želite da napravite pristupni kôd na drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ovaj menadžer lozinki će čuvati lozinke i pristupne kodove da biste se lako prijavljivali"</string>
<string name="set_as_default" msgid="4415328591568654603">"Podesi kao podrazumevano"</string>
<string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Pristupnih kodova:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index 99af511..6cad43d 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Скасаваць"</string>
<string name="string_continue" msgid="1346732695941131882">"Далей"</string>
<string name="string_more_options" msgid="7990658711962795124">"Дадатковыя параметры"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"З ключамі доступу вам будзе бяспечней."</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Дзякуючы ключам доступу вам не трэба ствараць і запамінаць складаныя паролі."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ключы доступу – гэта зашыфраваныя лючбавыя ключы, створаныя вамі з дапамогай адбітка пальца, твару ці блакіроўкі экрана."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Яны захаваны ў менеджары пароляў. Дзякуючы гэтаму вы можаце ўваходзіць на іншых прыладах"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Выберыце, куды захаваць <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Выберыце менеджар пароляў, каб захаваць свае даныя і забяспечыць хуткі ўваход у наступныя разы"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Стварыце ключ доступу да праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Захаваць пароль для праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Захаваць інфармацыю пра спосаб уваходу ў праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
<string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ключы доступу"</string>
+ <string name="passwords" msgid="5419394230391253816">"паролі"</string>
<string name="sign_ins" msgid="4710739369149469208">"спосабы ўваходу"</string>
<string name="sign_in_info" msgid="2627704710674232328">"інфармацыя пра спосабы ўваходу"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Захаваць <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> сюды:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Стварыць ключ доступу на іншай прыладзе?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Выкарыстоўваць папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" для ўсіх спосабаў уваходу?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Каб вам было прасцей уваходзіць у сістэму, вашы паролі і ключы доступу будуць захоўвацца ў менеджары пароляў"</string>
<string name="set_as_default" msgid="4415328591568654603">"Выкарыстоўваць стандартна"</string>
<string name="use_once" msgid="9027366575315399714">"Скарыстаць адзін раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Пароляў: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Ключоў доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index 13ebe24..163398e 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Отказ"</string>
<string name="string_continue" msgid="1346732695941131882">"Напред"</string>
<string name="string_more_options" msgid="7990658711962795124">"Още опции"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"По-сигурно с помощта на кодове за достъп"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Когато използвате кодове за достъп, не е необходимо да създавате, нито да помните сложни пароли"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Кодовете за достъп са шифровани дигитални ключове, които създавате посредством отпечатъка, лицето си или опцията си за заключване на екрана"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Данните се запазват в мениджър на пароли, за да можете да влизате в профила си на други устройства"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Изберете къде да запазите своите <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Изберете мениджър на пароли, в който да се запазят данните ви, така че следващия път да влезете по-бързо в профила си"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Да се създаде ли код за достъп за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Да се запази ли паролата за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Да се запазят ли данните за вход за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"код за достъп"</string>
<string name="password" msgid="6738570945182936667">"парола"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"кодове за достъп"</string>
+ <string name="passwords" msgid="5419394230391253816">"пароли"</string>
<string name="sign_ins" msgid="4710739369149469208">"данни за вход"</string>
<string name="sign_in_info" msgid="2627704710674232328">"данните за вход"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Запазване на <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> във:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Искате ли да създадете код за достъп на друго устройство?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Да се използва ли <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> за всичките ви данни за вход?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Този мениджър на пароли ще съхранява вашите пароли и кодове за достъп, за да влизате лесно в профила си"</string>
<string name="set_as_default" msgid="4415328591568654603">"Задаване като основно"</string>
<string name="use_once" msgid="9027366575315399714">"Еднократно използване"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> пароли • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кода за достъп"</string>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index a19fe71..408ccb1 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"বাতিল করুন"</string>
<string name="string_continue" msgid="1346732695941131882">"চালিয়ে যান"</string>
<string name="string_more_options" msgid="7990658711962795124">"আরও বিকল্প"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"\'পাসকী\'-এর সাথে সুরক্ষিত"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"\'পাসকী\' ব্যবহার করলে জটিল পাসওয়ার্ড তৈরি করার বা মনে রাখার কোনও প্রয়োজন নেই"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"আপনার ফিঙ্গারপ্রিন্ট, ফেস মডেল বা \'স্ক্রিন লক\' ব্যবহার করে আপনি যে এনক্রিপটেড ডিজিটাল \'কী\' তৈরি করেন সেগুলিই হল \'পাসকী\'"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"আপনি যাতে অন্যান্য ডিভাইসে সাইন-ইন করতে পারেন তার জন্য Password Manager-এ এগুলি সেভ করা হয়"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"আপনার <xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"আপনার তথ্য সেভ করতে একটি Password Manager বেছে নিন এবং পরের বার আরও দ্রুত সাইন-ইন করুন"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>-এর জন্য \'পাসকী\' তৈরি করবেন?"</string>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 6b776f5..6d3a184 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Otkaži"</string>
<string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
<string name="string_more_options" msgid="7990658711962795124">"Više opcija"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Saznajte više"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Sigurniji ste uz pristupne ključeve"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Uz pristupne ključeve ne morate kreirati ili pamtiti složene lozinke"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Pristupni ključevi su šifrirani digitalni ključevi koje kreirate pomoću otiska prsta, lica ili zaključavanja ekrana"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Pristupni ključevi se pohranjuju u upravitelju lozinki da se možete prijaviti na drugim uređajima"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Više informacija o pristupnim ključevima"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Tehnologija bez upotrebe zaporke"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Pristupni ključevi omogućuju prijavu bez upotrebe zaporki. Treba vam samo otisak prsta, prepoznavanje lica, PIN ili uzorak pokreta prstom da biste potvrdili svoj identitet i izradili pristupni ključ."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografija javnog ključa"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Na temelju saveza FIDO (koji uključuje Google, Apple, Microsoft i mnoge druge) i standarda W3C pristupni ključevi koriste kriptografske ključeve. Za razliku od korisničkog imena i niza znakova za zaporke, privatno-javni ključ izrađen je za aplikaciju ili web-lokaciju. Privatni ključ pohranjen je na vašem uređaju ili upravitelju zaporki i potvrđuje vaš identitet. Javni se ključ dijeli s poslužiteljem aplikacije ili web-lokacije. Uz odgovarajuće ključeve možete se odmah registrirati i prijaviti."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Poboljšana sigurnost računa"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Svaki ključ povezan isključivo s aplikacijom ili web-lokacijom za koju je izrađen, stoga se nikad ne možete pogreškom prijaviti u prijevarnu aplikaciju ili na web-lokaciju. Osim toga, kad je riječ o poslužiteljima na kojem se nalaze samo javni ključevi, hakiranje je mnogo teže."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Besprijekorni prijelaz"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Kako idemo u smjeru budućnosti bez zaporki, one će i dalje biti dostupne uz pristupne ključeve."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje sačuvati stavku <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja lozinki da sačuvate svoje informacije i brže se prijavite sljedeći put"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Kreirati pristupni ključ za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 8943f46..5d59484 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel·la"</string>
<string name="string_continue" msgid="1346732695941131882">"Continua"</string>
<string name="string_more_options" msgid="7990658711962795124">"Més opcions"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Més seguretat amb les claus d\'accés"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Amb les claus d\'accés, no cal que creïs ni recordis contrasenyes difícils"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Les claus d\'accés són claus digitals encriptades que pots crear amb la teva cara, l\'empremta digital o el bloqueig de pantalla"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Es desen a un gestor de contrasenyes perquè puguis iniciar la sessió en altres dispositius"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Tria on vols desar les <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contrasenyes per desar la teva informació i iniciar la sessió més ràpidament la pròxima vegada"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vols crear la clau d\'accés per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vols desar la contrasenya per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vols desar la informació d\'inici de sessió per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>
<string name="password" msgid="6738570945182936667">"contrasenya"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"claus d\'accés"</string>
+ <string name="passwords" msgid="5419394230391253816">"contrasenyes"</string>
<string name="sign_ins" msgid="4710739369149469208">"inicis de sessió"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informació d\'inici de sessió"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Desa <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> a"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vols crear una clau d\'accés en un altre dispositiu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vols utilitzar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per a tots els teus inicis de sessió?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Aquest gestor de contrasenyes emmagatzemarà les teves contrasenyes i claus d\'accés per ajudar-te a iniciar la sessió fàcilment"</string>
<string name="set_as_default" msgid="4415328591568654603">"Estableix com a predeterminada"</string>
<string name="use_once" msgid="9027366575315399714">"Utilitza un cop"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasenyes • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claus d\'accés"</string>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index 06f94d2..de5c5b6 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Zrušit"</string>
<string name="string_continue" msgid="1346732695941131882">"Pokračovat"</string>
<string name="string_more_options" msgid="7990658711962795124">"Další možnosti"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Další informace"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Přístupové klíče zvyšují bezpečnost"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"S přístupovými klíči si nemusíte vytvářet ani pamatovat složitá hesla"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Přístupové klíče jsou šifrované digitální klíče, které vytvoříte pomocí otisku prstu, obličeje nebo zámku obrazovky"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Přístupové klíče se ukládají do správce hesel, takže se můžete přihlásit na jiných zařízeních"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Další informace o přístupových klíčích"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Technologie bez hesel"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Přístupové klíče umožňují přihlašovat se bez hesel. Stačí pomocí otisku prstu, rozpoznání obličeje, kódu PIN nebo gesta ověřit svou totožnost a vytvořit přístupový klíč."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kryptografie s veřejným klíčem"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Podle pokynů FIDO Alliance (která zahrnuje společnosti Google, Apple, Microsoft a další) a standardů W3C používají přístupové klíče páry kryptografických klíčů. Na rozdíl od uživatelského jména a řetězce znaků, které používáme pro hesla, se pro aplikaci nebo web vytváří pár klíčů (soukromého a veřejného ). Soukromý klíč je bezpečně uložen ve vašem zařízení nebo správci hesel a potvrzuje vaši identitu. Veřejný klíč je sdílen s aplikací nebo webovým serverem. Pomocí odpovídajících klíčů se můžete okamžitě zaregistrovat a přihlásit."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Vylepšené zabezpečení účtu"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Každý klíč je propojen výhradně s aplikací nebo webem, pro které byl vytvořen, takže se nikdy nemůžete omylem přihlásit k podvodné aplikaci nebo webu. Protože na serverech jsou uloženy pouze veřejné klíče, je hackování navíc mnohem obtížnější."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Bezproblémový přechod"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Ačkoliv směřujeme k budoucnosti bez hesel, vedle přístupových klíčů budou stále k dispozici i hesla."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Určete, kam ukládat <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správce hesel k uložení svých údajů, abyste se příště mohli přihlásit rychleji"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vytvořit přístupový klíč pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Uložit heslo pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Uložit přihlašovací údaje pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"přístupový klíč"</string>
<string name="password" msgid="6738570945182936667">"heslo"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"přístupové klíče"</string>
+ <string name="passwords" msgid="5419394230391253816">"hesla"</string>
<string name="sign_ins" msgid="4710739369149469208">"přihlášení"</string>
<string name="sign_in_info" msgid="2627704710674232328">"přihlašovací údaje"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Uložit <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> do"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vytvořit přístupový klíč v jiném zařízení?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Používat <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pro všechna přihlášení?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Tento správce hesel bude ukládat vaše hesla a přístupové klíče, abyste se mohli snadno přihlásit"</string>
<string name="set_as_default" msgid="4415328591568654603">"Nastavit jako výchozí"</string>
<string name="use_once" msgid="9027366575315399714">"Použít jednou"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Hesla: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Přístupové klíče: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index 4c68886..86135b0 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Annuller"</string>
<string name="string_continue" msgid="1346732695941131882">"Fortsæt"</string>
<string name="string_more_options" msgid="7990658711962795124">"Flere valgmuligheder"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Øget beskyttelse med adgangsnøgler"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Når du bruger adgangsnøgler, behøver du ikke at oprette eller huske avancerede adgangskoder"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Adgangsnøgler er krypterede digitale nøgler, som du opretter ved hjælp af fingeraftryk, ansigtsgenkendelse eller skærmlås"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Disse gemmes i en adgangskodeadministrator, så du kan logge ind på andre enheder"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Vælg, hvor du vil gemme dine <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Vælg en adgangskodeadministrator for at gemme dine oplysninger, så du kan logge ind hurtigere næste gang"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vil du oprette en adgangsnøgle til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vil du gemme adgangskoden til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du gemme loginoplysningerne til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>
<string name="password" msgid="6738570945182936667">"adgangskode"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"adgangsnøgler"</string>
+ <string name="passwords" msgid="5419394230391253816">"adgangskoder"</string>
<string name="sign_ins" msgid="4710739369149469208">"loginmetoder"</string>
<string name="sign_in_info" msgid="2627704710674232328">"loginoplysninger"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Gem <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> her:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vil du oprette en adgangsnøgle på en anden enhed?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruge <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> til alle dine loginmetoder?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Denne adgangskodeadministrator gemmer dine adgangskoder og adgangsnøgler for at hjælpe dig med nemt at logge ind"</string>
<string name="set_as_default" msgid="4415328591568654603">"Angiv som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Brug én gang"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> adgangskoder • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> adgangsnøgler"</string>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index d26f430..8da48c1 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Abbrechen"</string>
<string name="string_continue" msgid="1346732695941131882">"Weiter"</string>
<string name="string_more_options" msgid="7990658711962795124">"Weitere Optionen"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mehr Sicherheit mit Passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Mit Passkeys musst du keine komplizierten Passwörter erstellen oder dir merken"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys sind verschlüsselte digitale Schlüssel, die du mithilfe deines Fingerabdrucks, Gesichts oder deiner Displaysperre erstellst"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Sie werden in einem Passwortmanager gespeichert, damit du dich auf anderen Geräten anmelden kannst"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Wähle aus, wo deine <xliff:g id="CREATETYPES">%1$s</xliff:g> gespeichert werden sollen"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Du kannst einen Passwortmanager auswählen, um deine Anmeldedaten zu speichern, damit du dich nächstes Mal schneller anmelden kannst"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Passkey für <xliff:g id="APPNAME">%1$s</xliff:g> erstellen?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Passwort für <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Anmeldedaten für <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
<string name="passkey" msgid="632353688396759522">"Passkey"</string>
<string name="password" msgid="6738570945182936667">"Passwort"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"Passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"Passwörter"</string>
<string name="sign_ins" msgid="4710739369149469208">"Anmeldungen"</string>
<string name="sign_in_info" msgid="2627704710674232328">"Anmeldedaten"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> speichern unter"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Passkey auf einem anderen Gerät erstellen?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> für alle Anmeldungen verwenden?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Mit diesem Passwortmanager werden deine Passwörter und Passkeys gespeichert, damit du dich problemlos anmelden kannst"</string>
<string name="set_as_default" msgid="4415328591568654603">"Als Standard festlegen"</string>
<string name="use_once" msgid="9027366575315399714">"Einmal verwenden"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> Passwörter • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> Passkeys"</string>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 3fb6506..f99b5f0 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Ακύρωση"</string>
<string name="string_continue" msgid="1346732695941131882">"Συνέχεια"</string>
<string name="string_more_options" msgid="7990658711962795124">"Περισσότερες επιλογές"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Μεγαλύτερη ασφάλεια με κλειδιά πρόσβασης"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Με τα κλειδιά πρόσβασης, δεν χρειάζεται να δημιουργείτε ή να θυμάστε σύνθετους κωδικούς πρόσβασης."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Τα κλειδιά πρόσβασης είναι κρυπτογραφημένα ψηφιακά κλειδιά που δημιουργείτε χρησιμοποιώντας το δακτυλικό σας αποτύπωμα, το πρόσωπο ή το κλείδωμα οθόνης."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Αποθηκεύονται σε ένα πρόγραμμα διαχείρισης κωδικών πρόσβασης, για να μπορείτε να συνδέεστε από άλλες συσκευές."</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Επιλέξτε πού θα αποθηκεύονται τα <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Επιλέξτε ένα πρόγραμμα διαχείρισης κωδικών πρόσβασης για να αποθηκεύσετε τα στοιχεία σας και να συνδεθείτε πιο γρήγορα την επόμενη φορά."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Δημιουργία κλειδιού πρόσβασης για <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 0bccea1..76b58c7 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
<string name="string_continue" msgid="1346732695941131882">"Continue"</string>
<string name="string_more_options" msgid="7990658711962795124">"More options"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Learn more"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"With passkeys, you don’t need to create or remember complex passwords"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys are encrypted digital keys that you create using your fingerprint, face or screen lock"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"They are saved to a password manager, so that you can sign in on other devices"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"More about passkeys"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwordless technology"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkeys allow you to sign in without relying on passwords. You just need to use your fingerprint, face recognition, PIN or swipe pattern to verify your identity and create a passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index 38637df..5277f67 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
<string name="string_continue" msgid="1346732695941131882">"Continue"</string>
<string name="string_more_options" msgid="7990658711962795124">"More options"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Learn more"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"With passkeys, you don’t need to create or remember complex passwords"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys are encrypted digital keys you create using your fingerprint, face, or screen lock"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"They are saved to a password manager, so you can sign in on other devices"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"More about passkeys"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwordless technology"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkeys allow you to sign in without relying on passwords. You just need to use your fingerprint, face recognition, PIN, or swipe pattern to verify your identity and create a passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft, and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 0bccea1..76b58c7 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
<string name="string_continue" msgid="1346732695941131882">"Continue"</string>
<string name="string_more_options" msgid="7990658711962795124">"More options"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Learn more"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"With passkeys, you don’t need to create or remember complex passwords"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys are encrypted digital keys that you create using your fingerprint, face or screen lock"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"They are saved to a password manager, so that you can sign in on other devices"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"More about passkeys"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwordless technology"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkeys allow you to sign in without relying on passwords. You just need to use your fingerprint, face recognition, PIN or swipe pattern to verify your identity and create a passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 0bccea1..76b58c7 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
<string name="string_continue" msgid="1346732695941131882">"Continue"</string>
<string name="string_more_options" msgid="7990658711962795124">"More options"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Learn more"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"With passkeys, you don’t need to create or remember complex passwords"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys are encrypted digital keys that you create using your fingerprint, face or screen lock"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"They are saved to a password manager, so that you can sign in on other devices"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"More about passkeys"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwordless technology"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkeys allow you to sign in without relying on passwords. You just need to use your fingerprint, face recognition, PIN or swipe pattern to verify your identity and create a passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index 081cfe8..9ea9cf5 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
<string name="string_continue" msgid="1346732695941131882">"Continue"</string>
<string name="string_more_options" msgid="7990658711962795124">"More options"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Learn more"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"With passkeys, you don’t need to create or remember complex passwords"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys are encrypted digital keys you create using your fingerprint, face, or screen lock"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"They are saved to a password manager, so you can sign in on other devices"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"More about passkeys"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwordless technology"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkeys allow you to sign in without relying on passwords. You just need to use your fingerprint, face recognition, PIN, or swipe pattern to verify your identity and create a passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft, and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index 9a6c3f3..5ea787f 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Más opciones"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Más seguridad con llaves de acceso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Con las llaves de acceso, no es necesario crear ni recordar contraseñas complejas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Las llaves de acceso son claves digitales encriptadas que puedes crear usando tu huella dactilar, rostro o bloqueo de pantalla"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Se guardan en un administrador de contraseñas para que puedas acceder en otros dispositivos"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un administrador de contraseñas para guardar tu información y acceder más rápido la próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"¿Quieres crear una llave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"¿Quieres guardar la contraseña para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Quieres guardar la información de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string>
+ <string name="passwords" msgid="5419394230391253816">"contraseñas"</string>
<string name="sign_ins" msgid="4710739369149469208">"accesos"</string>
<string name="sign_in_info" msgid="2627704710674232328">"información de acceso"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Guardar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> en"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"¿Quieres crear una llave de acceso en otro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Quieres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus accesos?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Este administrador de contraseñas almacenará tus contraseñas y llaves de acceso para ayudarte a acceder fácilmente"</string>
<string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> llaves de acceso"</string>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index 73f6e2f..c685bc2 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Más opciones"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Más seguridad con las llaves de acceso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Con las llaves de acceso, no tienes que crear ni recordar contraseñas complicadas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Las llaves de acceso son claves digitales cifradas que puedes crear con tu huella digital, cara o bloqueo de pantalla"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Se guardan en un gestor de contraseñas para que puedas iniciar sesión en otros dispositivos"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contraseñas para guardar tu información e iniciar sesión más rápido la próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"¿Crear llave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"¿Guardar la contraseña de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Guardar la información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string>
+ <string name="passwords" msgid="5419394230391253816">"contraseñas"</string>
<string name="sign_ins" msgid="4710739369149469208">"inicios de sesión"</string>
<string name="sign_in_info" msgid="2627704710674232328">"información de inicio de sesión"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Guardar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> en"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"¿Crear llave de acceso en otro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus inicios de sesión?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Este gestor de contraseñas almacenará tus contraseñas y llaves de acceso para que puedas iniciar sesión fácilmente"</string>
<string name="set_as_default" msgid="4415328591568654603">"Fijar como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> llaves de acceso"</string>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 597ad7f..30a823d 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Tühista"</string>
<string name="string_continue" msgid="1346732695941131882">"Jätka"</string>
<string name="string_more_options" msgid="7990658711962795124">"Rohkem valikuid"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Pääsuvõtmed suurendavad turvalisust"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Pääsuvõtmetega ei pea te looma ega meelde jätma keerukaid paroole"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Pääsuvõtmed on digitaalsed krüpteeritud võtmed, mille loote sõrmejälje, näo või ekraanilukuga"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Need salvestatakse paroolihaldurisse, et saaksite teistes seadmetes sisse logida"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Valige, kuhu soovite oma <xliff:g id="CREATETYPES">%1$s</xliff:g> salvestada"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Valige paroolihaldur, et salvestada oma teave ja järgmisel korral kiiremini sisse logida"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Kas luua rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks pääsuvõti?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Kas salvestada rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks parool?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Kas salvestada rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks sisselogimisandmed?"</string>
<string name="passkey" msgid="632353688396759522">"pääsukood"</string>
<string name="password" msgid="6738570945182936667">"parool"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"pääsuvõtmed"</string>
+ <string name="passwords" msgid="5419394230391253816">"paroolid"</string>
<string name="sign_ins" msgid="4710739369149469208">"sisselogimisandmed"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sisselogimisteave"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Salvestage <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Kas luua pääsuvõti muus seadmes?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Kas kasutada teenust <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kõigi teie sisselogimisandmete puhul?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"See paroolihaldur salvestab teie paroolid ja pääsuvõtmed, et aidata teil hõlpsalt sisse logida"</string>
<string name="set_as_default" msgid="4415328591568654603">"Määra vaikeseadeks"</string>
<string name="use_once" msgid="9027366575315399714">"Kasuta ühe korra"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parooli • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> pääsuvõtit"</string>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index 0178141..0ca9df7 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Utzi"</string>
<string name="string_continue" msgid="1346732695941131882">"Egin aurrera"</string>
<string name="string_more_options" msgid="7990658711962795124">"Aukera gehiago"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Sarbide-gako seguruagoak"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Sarbide-gakoei esker, ez duzu pasahitz konplexurik sortu edo gogoratu beharrik"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Hatz-marka, aurpegia edo pantailaren blokeoa erabilita sortzen dituzun giltza digital enkriptatuak dira sarbide-gakoak"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Pasahitz-kudeatzaile batean gordetzen dira, beste gailu batzuen bidez saioa hasi ahal izateko"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Aukeratu non gorde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Hautatu informazioa gordetzeko pasahitz-kudeatzaile bat eta hasi saioa bizkorrago hurrengoan"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> atzitzeko sarbide-gako bat sortu nahi duzu?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioko pasahitza gorde nahi duzu?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioko saioa hasteko informazioa gorde nahi duzu?"</string>
<string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>
<string name="password" msgid="6738570945182936667">"pasahitza"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"sarbide-gakoak"</string>
+ <string name="passwords" msgid="5419394230391253816">"pasahitzak"</string>
<string name="sign_ins" msgid="4710739369149469208">"kredentzialak"</string>
<string name="sign_in_info" msgid="2627704710674232328">"saioa hasteko informazioa"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Gorde <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> hemen:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Beste gailu batean sortu nahi duzu sarbide-gakoa?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> erabili nahi duzu kredentzial guztietarako?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Pasahitz-kudeatzaile honek pasahitzak eta sarbide-gakoak gordeko ditu saioa erraz has dezazun"</string>
<string name="set_as_default" msgid="4415328591568654603">"Ezarri lehenetsi gisa"</string>
<string name="use_once" msgid="9027366575315399714">"Erabili behin"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> pasahitz • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> sarbide-gako"</string>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index 1b11819..47325b5 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"لغو"</string>
<string name="string_continue" msgid="1346732695941131882">"ادامه"</string>
<string name="string_more_options" msgid="7990658711962795124">"گزینههای بیشتر"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"فضایی ایمنتر با گذرکلید"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"با گذرکلیدها، لازم نیست گذرواژه پیچیدهای بسازید یا آن را بهخاطر بسپارید"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"گذرکلیدها کلیدهای دیجیتالی رمزگذاریشدهای هستند که بااستفاده از اثر انگشت، چهره، یا قفل صفحه ایجاد میکنید"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"گذرکلیدها در «مدیر گذرواژه» ذخیره میشود تا بتوانید در دستگاههای دیگر به سیستم وارد شوید"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"جایی را برای ذخیره کردن <xliff:g id="CREATETYPES">%1$s</xliff:g> انتخاب کنید"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"مدیر گذرواژهای انتخاب کنید تا اطلاعاتتان ذخیره شود و دفعه بعدی سریعتر به سیستم وارد شوید"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"برای <xliff:g id="APPNAME">%1$s</xliff:g> گذرکلید ایجاد شود؟"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"گذرواژه <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"اطلاعات ورود به سیستم <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string>
<string name="passkey" msgid="632353688396759522">"گذرکلید"</string>
<string name="password" msgid="6738570945182936667">"گذرواژه"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"گذرکلیدها"</string>
+ <string name="passwords" msgid="5419394230391253816">"گذرواژهها"</string>
<string name="sign_ins" msgid="4710739369149469208">"ورود به سیستمها"</string>
<string name="sign_in_info" msgid="2627704710674232328">"اطلاعات ورود به سیستم"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"ذخیره <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> در"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"گذرکلید در دستگاه دیگر ایجاد شود؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"از <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> برای همه ورود به سیستمها استفاده شود؟"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"این مدیر گذرواژه گذرکلیدها و گذرواژههای شما را ذخیره خواهد کرد تا بهراحتی بتوانید به سیستم وارد شوید"</string>
<string name="set_as_default" msgid="4415328591568654603">"تنظیم بهعنوان پیشفرض"</string>
<string name="use_once" msgid="9027366575315399714">"یکبار استفاده"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> گذرکلید"</string>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index bdb55fb..6dff909 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Peru"</string>
<string name="string_continue" msgid="1346732695941131882">"Jatka"</string>
<string name="string_more_options" msgid="7990658711962795124">"Lisäasetukset"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Turvallisuutta avainkoodeilla"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Kun käytät avainkoodeja, sinun ei tarvitse luoda tai muistaa monimutkaisia salasanoja"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Avainkoodit ovat salattuja digitaalisia avaimia, joita voit luoda sormenjäljen, kasvojen tai näytön lukituksen avulla"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ne tallennetaan salasanojen ylläpito-ohjelmaan, jotta voit kirjautua sisään muilla laitteilla"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Valitse, minne <xliff:g id="CREATETYPES">%1$s</xliff:g> tallennetaan"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Valitse salasanojen ylläpitotyökalu, niin voit tallentaa tietosi ja kirjautua ensi kerralla nopeammin sisään"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Luodaanko avainkoodi (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Tallennetaanko salasana (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Tallennetaanko kirjautumistiedot (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
<string name="passkey" msgid="632353688396759522">"avainkoodi"</string>
<string name="password" msgid="6738570945182936667">"salasana"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"avainkoodit"</string>
+ <string name="passwords" msgid="5419394230391253816">"salasanat"</string>
<string name="sign_ins" msgid="4710739369149469208">"sisäänkirjautumiset"</string>
<string name="sign_in_info" msgid="2627704710674232328">"kirjautumistiedot"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Tallenna <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> tänne:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Luodaanko avainkoodi toisella laitteella?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Otetaanko <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> käyttöön kaikissa sisäänkirjautumisissa?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Tämä salasanojen ylläpitotyökalu tallentaa salasanat ja avainkoodit, jotta voit kirjautua helposti sisään"</string>
<string name="set_as_default" msgid="4415328591568654603">"Aseta oletukseksi"</string>
<string name="use_once" msgid="9027366575315399714">"Käytä kerran"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> salasanaa • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> avainkoodia"</string>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index 1e4b009..c501178 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Annuler"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuer"</string>
<string name="string_more_options" msgid="7990658711962795124">"Autres options"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Une sécurité accrue grâce aux clés d\'accès"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Avec les clés d\'accès, nul besoin de créer ou de mémoriser des mots de passe complexes"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Les clés d\'accès sont des clés numériques chiffrées que vous créez en utilisant votre empreinte digitale, votre visage ou le verrouillage de votre écran"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ils sont enregistrés dans un gestionnaire de mots de passe pour vous permettre de vous connecter sur d\'autres appareils"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Choisir où sauvegarder vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos renseignements et vous connecter plus rapidement la prochaine fois"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Créer une clé d\'accès pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Enregistrer le mot de passe pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les renseignements de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string>
+ <string name="passwords" msgid="5419394230391253816">"mots de passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
<string name="sign_in_info" msgid="2627704710674232328">"renseignements de connexion"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Enregistrer <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> dans"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Créer une clé d\'accès dans un autre appareil?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ce gestionnaire de mots de passe stockera vos mots de passe et vos clés d\'accès pour vous permettre de vous connecter facilement"</string>
<string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
<string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index 7073ca6..05a0601 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Annuler"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuer"</string>
<string name="string_more_options" msgid="7990658711962795124">"Autres options"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Sécurité renforcée grâce aux clés d\'accès"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Avec les clés d\'accès, plus besoin de créer ni de mémoriser des mots de passe complexes"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Les clés d\'accès sont des clés numériques chiffrées que vous créez à l\'aide de votre empreinte digitale, de votre visage ou du verrouillage de l\'écran"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Elles sont enregistrées dans un gestionnaire de mots de passe pour que vous puissiez vous connecter sur d\'autres appareils"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Choisissez où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos informations et vous connecter plus rapidement la prochaine fois"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Créer une clé d\'accès pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Enregistrer le mot de passe pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les informations de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string>
+ <string name="passwords" msgid="5419394230391253816">"mots de passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informations de connexion"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Enregistrer la <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> dans"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Créer une clé d\'accès sur un autre appareil ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ce gestionnaire de mots de passe stockera vos mots de passe et clés d\'accès pour vous permettre de vous connecter facilement"</string>
<string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
<string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mot(s) de passe • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clé(s) d\'accès"</string>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index 5b6e719..4fb09cc 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Máis opcións"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Máis protección coas claves de acceso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Cunha clave de acceso, non é necesario que crees ou lembres contrasinais complexos"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"As claves de acceso son claves dixitais encriptadas que creas usando a túa impresión dixital, a túa cara ou o teu bloqueo de pantalla"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"As claves de acceso gárdanse nun xestor de contrasinais para que poidas iniciar sesión noutros dispositivos"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Escolle onde queres gardar: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un xestor de contrasinais para gardar a túa información e iniciar sesión máis rápido a próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Queres crear unha clave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Queres gardar o contrasinal de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Queres gardar a información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"clave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contrasinal"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"claves de acceso"</string>
+ <string name="passwords" msgid="5419394230391253816">"contrasinais"</string>
<string name="sign_ins" msgid="4710739369149469208">"métodos de inicio de sesión"</string>
<string name="sign_in_info" msgid="2627704710674232328">"información de inicio de sesión"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Gardar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> en"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Queres crear unha clave de acceso noutro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Queres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cada vez que inicies sesión?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Este xestor de contrasinais almacenará os contrasinais e as claves de acceso para axudarche a iniciar sesión facilmente"</string>
<string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar unha vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasinais • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claves de acceso"</string>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index fdaf586..6afc6e6 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"રદ કરો"</string>
<string name="string_continue" msgid="1346732695941131882">"ચાલુ રાખો"</string>
<string name="string_more_options" msgid="7990658711962795124">"વધુ વિકલ્પો"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"વધુ જાણો"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"પાસકી સાથે વધુ સલામત"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"પાસકી હોવાથી, તમારે જટિલ પાસવર્ડ બનાવવાની કે યાદ રાખવાની જરૂર રહેતી નથી"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"પાસકી એ એન્ક્રિપ્ટેડ ડિજિટલ કી છે, જેને તમે તમારી ફિંગરપ્રિન્ટ, ચહેરા અથવા સ્ક્રીન લૉકનો ઉપયોગ કરીને બનાવો છો"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"તેને પાસવર્ડ મેનેજરમાં સાચવવામાં આવે છે, જેથી તમે અન્ય ડિવાઇસમાં સાઇન ઇન ન કરી શકો"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"પાસકી વિશે વધુ"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"પાસવર્ડ રહિત ટેક્નોલોજી"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"પાસકી તમને પાસવર્ડ પર આધાર રાખ્યા વિના સાઇન ઇન કરવાની મંજૂરી આપે છે. તમારી ઓળખની ચકાસણી કરીને તમારી પાસકી બનાવવા માટે, તમારે માત્ર તમારી ફિંગરપ્રિન્ટ, ચહેરાની ઓળખ, પિન અથવા સ્વાઇપ પૅટર્નનો ઉપયોગ કરવાની જરૂર છે."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"જાહેર કીની ક્રિપ્ટોગ્રાફી"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ભાગીદારી (જેમાં Google, Apple, Microsoft અને વધુનો સમાવેશ થાય છે) અને W3C સ્ટૅન્ડર્ડના આધારે, પાસકી ક્રિપ્ટોગ્રાફિક કીની જોડીનો ઉપયોગ કરે છે. આપણે પાસવર્ડ માટે ઉપયોગ કરીએ છીએ તે વપરાશકર્તાનામ અને અક્ષરોની સ્ટ્રિંગથી વિપરીત, ઍપ કે વેબસાઇટ માટે એક ખાનગી-જાહેર કીની જોડી બને છે. ખાનગી કી તમારા ડિવાઇસ અથવા પાસવર્ડ મેનેજરમાં સુરક્ષિત રીતે સ્ટોર થાય છે અને તે તમારી ઓળખ કન્ફર્મ કરે છે. જાહેર કી ઍપ કે વેબસાઇટના સર્વર સાથે શેર કરવામાં આવે છે. અનુરૂપ કી સાથે, તમે તરત જ રજિસ્ટર અને સાઇન ઇન કરી શકો છો."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"બહેતર બનાવેલી એકાઉન્ટની સુરક્ષા"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"દરેક કીને જે ઍપ અથવા વેબસાઇટ માટે બનાવવામાં આવી હોય તેની સાથે તે વિશેષ રીતે લિંક થયેલી છે, તેથી તમારાથી ક્યારેય ભૂલથી કપટપૂર્ણ ઍપ અથવા વેબસાઇટ પર સાઇન ઇન ન થાય. ઉપરાંત, સર્વર માત્ર જાહેર કી રાખે છે, હૅકિંગ ઘણું મુશ્કેલ છે."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"વિક્ષેપરહિત ટ્રાન્ઝિશન"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"આપણે પાસવર્ડ રહિત ભવિષ્ય તરફ આગળ વધી રહ્યાં છીએ, છતાં પાસકીની સાથોસાથ હજી પણ પાસવર્ડ ઉપલબ્ધ રહેશે."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"તમારી <xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી તે પસંદ કરો"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"તમારી માહિતી સાચવવા માટે પાસવર્ડ મેનેજર પસંદ કરો અને આગલી વખતે વધુ ઝડપથી સાઇન ઇન કરો"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે પાસકી બનાવીએ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે પાસવર્ડ સાચવીએ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે સાઇન-ઇન કરવાની માહિતી સાચવીએ?"</string>
<string name="passkey" msgid="632353688396759522">"પાસકી"</string>
<string name="password" msgid="6738570945182936667">"પાસવર્ડ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"પાસકી"</string>
+ <string name="passwords" msgid="5419394230391253816">"પાસવર્ડ"</string>
<string name="sign_ins" msgid="4710739369149469208">"સાઇન-ઇન"</string>
<string name="sign_in_info" msgid="2627704710674232328">"સાઇન-ઇન કરવાની માહિતી"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>ને આમાં સાચવો"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"અન્ય ડિવાઇસ પર પાસકી બનાવીએ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"શું તમારા બધા સાઇન-ઇન માટે <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>નો ઉપયોગ કરીએ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"આ પાસવર્ડ મેનેજર તમને સરળતાથી સાઇન ઇન કરવામાં સહાય કરવા માટે, તમારા પાસવર્ડ અને પાસકી સ્ટોર કરશે"</string>
<string name="set_as_default" msgid="4415328591568654603">"ડિફૉલ્ટ તરીકે સેટ કરો"</string>
<string name="use_once" msgid="9027366575315399714">"એકવાર ઉપયોગ કરો"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> પાસવર્ડ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> પાસકી"</string>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index f75a989..6cc26c5 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"रद्द करें"</string>
<string name="string_continue" msgid="1346732695941131882">"जारी रखें"</string>
<string name="string_more_options" msgid="7990658711962795124">"ज़्यादा विकल्प"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकी के साथ सुरक्षित रहें"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"पासकी होने पर, आपको जटिल पासवर्ड बनाने या याद रखने की ज़रूरत नहीं पड़ती"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"पासकी, एन्क्रिप्ट (सुरक्षित) की गई डिजिटल की होती हैं. इन्हें फ़िंगरप्रिंट, चेहरे या स्क्रीन लॉक का इस्तेमाल करके बनाया जाता है"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"पासकी को पासवर्ड मैनेजर में सेव किया जाता है, ताकि इनका इस्तेमाल करके आप अन्य डिवाइसों में साइन इन कर सकें"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"चुनें कि अपनी <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां सेव करनी हैं"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"अपनी जानकारी सेव करने के लिए, कोई पासवर्ड मैनेजर चुनें और अगली बार तेज़ी से साइन इन करें"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए पासकी बनानी है?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए पासवर्ड सेव करना है?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए साइन-इन की जानकारी सेव करनी है?"</string>
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"पासकी"</string>
+ <string name="passwords" msgid="5419394230391253816">"पासवर्ड"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन इन"</string>
<string name="sign_in_info" msgid="2627704710674232328">"साइन-इन की जानकारी"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> को यहां सेव करें"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"क्या किसी दूसरे डिवाइस में पासकी सेव करनी है?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"क्या आपको साइन इन से जुड़ी सारी जानकारी सेव करने के लिए, <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> का इस्तेमाल करना है?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"यह पासवर्ड मैनेजर, आपके पासवर्ड और पासकी सेव करेगा, ताकि आपको साइन इन करने में आसानी हो"</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफ़ॉल्ट के तौर पर सेट करें"</string>
<string name="use_once" msgid="9027366575315399714">"इसका इस्तेमाल एक बार किया जा सकता है"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 2f9e46b..aff78ff 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Odustani"</string>
<string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
<string name="string_more_options" msgid="7990658711962795124">"Više opcija"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Saznajte više"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Sigurniji s pristupnim ključevima"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Uz pristupne ključeve ne trebate izrađivati ili pamtiti složene zaporke"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Pristupni ključevi šifrirani su digitalni ključevi koje izrađujete pomoću svojeg otiska prsta, lica ili zaključavanja zaslona"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Spremaju se u upravitelju zaporki kako biste se mogli prijaviti na drugim uređajima"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Više informacija o pristupnim ključevima"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Tehnologija bez upotrebe zaporke"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Pristupni ključevi omogućuju prijavu bez upotrebe zaporki. Treba vam samo otisak prsta, prepoznavanje lica, PIN ili uzorak pokreta prstom da biste potvrdili svoj identitet i izradili pristupni ključ."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografija javnog ključa"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Na temelju saveza FIDO (koji uključuje Google, Apple, Microsoft i mnoge druge) i standarda W3C pristupni ključevi koriste kriptografske ključeve. Za razliku od korisničkog imena i niza znakova za zaporke, privatno-javni ključ izrađen je za aplikaciju ili web-lokaciju. Privatni ključ pohranjen je na vašem uređaju ili upravitelju zaporki i potvrđuje vaš identitet. Javni se ključ dijeli s poslužiteljem aplikacije ili web-lokacije. Uz odgovarajuće ključeve možete se odmah registrirati i prijaviti."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Poboljšana sigurnost računa"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Svaki ključ povezan isključivo s aplikacijom ili web-lokacijom za koju je izrađen, stoga se nikad ne možete pogreškom prijaviti u prijevarnu aplikaciju ili na web-lokaciju. Osim toga, kad je riječ o poslužiteljima na kojem se nalaze samo javni ključevi, hakiranje je mnogo teže."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Besprijekorni prijelaz"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Kako idemo u smjeru budućnosti bez zaporki, one će i dalje biti dostupne uz pristupne ključeve."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Odaberite mjesto za spremanje: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja zaporki kako biste spremili svoje informacije i drugi se put brže prijavili"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Izraditi pristupni ključ za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 81616df..f9efc85 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Mégse"</string>
<string name="string_continue" msgid="1346732695941131882">"Folytatás"</string>
<string name="string_more_options" msgid="7990658711962795124">"További lehetőségek"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Fokozott biztonság – azonosítókulccsal"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Azonosítókulcs birtokában nincs szükség összetett jelszavak létrehozására vagy megjegyzésére"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Az azonosítókulcsok olyan digitális kulcsok, amelyeket ujjlenyomata, arca vagy képernyőzár használatával hoz létre"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Az azonosítókulcsokat a rendszer jelszókezelőbe menti, így más eszközökbe is be tud jelentkezni"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Válassza ki, hogy hova szeretné menteni <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Válasszon jelszókezelőt, hogy menthesse az adatait, és gyorsabban jelentkezhessen be a következő alkalommal."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Létrehoz azonosítókulcsot a következőhöz: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Szeretné elmenteni a(z) <xliff:g id="APPNAME">%1$s</xliff:g> jelszavát?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Menti a bejelentkezési adatokat a következőhöz: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>
<string name="password" msgid="6738570945182936667">"jelszó"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"azonosítókulcsait"</string>
+ <string name="passwords" msgid="5419394230391253816">"jelszavait"</string>
<string name="sign_ins" msgid="4710739369149469208">"bejelentkezési adatok"</string>
<string name="sign_in_info" msgid="2627704710674232328">"bejelentkezési adatok"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> mentése ide:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Egy másik eszközön szeretne azonosítókulcsot létrehozni?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Szeretné a következőt használni az összes bejelentkezési adatához: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ez a jelszókezelő fogja tárolni a jelszavait és azonosítókulcsait a bejelentkezés megkönnyítése érdekében."</string>
<string name="set_as_default" msgid="4415328591568654603">"Beállítás alapértelmezettként"</string>
<string name="use_once" msgid="9027366575315399714">"Egyszeri használat"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> jelszó, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> azonosítókulcs"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index 782b2d9..790ee8f 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Չեղարկել"</string>
<string name="string_continue" msgid="1346732695941131882">"Շարունակել"</string>
<string name="string_more_options" msgid="7990658711962795124">"Այլ տարբերակներ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Անցաբառերի հետ ավելի ապահով է"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Անցաբառերի շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Անցաբառերը գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ անցաբառերը պահվում են գաղտնաբառերի կառավարիչում"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Նշեք, թե որտեղ եք ուզում պահել ձեր <xliff:g id="CREATETYPES">%1$s</xliff:g>ը"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Ընտրեք գաղտնաբառերի կառավարիչ՝ ձեր տեղեկությունները պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ստեղծե՞լ անցաբառ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի համար"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի գաղտնաբառը"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի մուտքի տվյալները"</string>
<string name="passkey" msgid="632353688396759522">"անցաբառ"</string>
<string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"անցաբառեր"</string>
+ <string name="passwords" msgid="5419394230391253816">"գաղտնաբառեր"</string>
<string name="sign_ins" msgid="4710739369149469208">"մուտք"</string>
<string name="sign_in_info" msgid="2627704710674232328">"մուտքի տվյալներ"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Պահել <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>ն այստեղ՝"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Ստեղծե՞լ անցաբառ այլ սարքում"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Միշտ մուտք գործե՞լ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածի միջոցով"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Գաղտնաբառերի այս կառավարիչը կպահի ձեր գաղտնաբառերն ու անցաբառերը՝ օգնելու ձեզ հեշտությամբ մուտք գործել հաշիվ"</string>
<string name="set_as_default" msgid="4415328591568654603">"Նշել որպես կանխադրված"</string>
<string name="use_once" msgid="9027366575315399714">"Օգտագործել մեկ անգամ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> անցաբառ"</string>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index f16a321..b3d42d0 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Batal"</string>
<string name="string_continue" msgid="1346732695941131882">"Lanjutkan"</string>
<string name="string_more_options" msgid="7990658711962795124">"Opsi lainnya"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Lebih aman dengan kunci sandi"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Dengan kunci sandi, Anda tidak perlu membuat atau mengingat sandi yang rumit"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Kunci sandi adalah kunci digital terenkripsi yang Anda buat menggunakan sidik jari, wajah, atau kunci layar"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Kunci sandi disimpan ke pengelola sandi, sehingga Anda dapat login di perangkat lainnya"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat penyimpanan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Pilih pengelola sandi untuk menyimpan info Anda dan login lebih cepat pada waktu berikutnya"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Buat kunci sandi untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Simpan sandi untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan info login untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"kunci sandi"</string>
<string name="password" msgid="6738570945182936667">"sandi"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"kunci sandi"</string>
+ <string name="passwords" msgid="5419394230391253816">"sandi"</string>
<string name="sign_ins" msgid="4710739369149469208">"login"</string>
<string name="sign_in_info" msgid="2627704710674232328">"info login"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Simpan <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ke"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Buat kunci sandi di perangkat lain?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua info login Anda?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Pengelola sandi ini akan menyimpan sandi dan kunci sandi untuk membantu Anda login dengan mudah"</string>
<string name="set_as_default" msgid="4415328591568654603">"Setel sebagai default"</string>
<string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> sandi • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> kunci sandi"</string>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index 170cd9a..d13c991 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Hætta við"</string>
<string name="string_continue" msgid="1346732695941131882">"Áfram"</string>
<string name="string_more_options" msgid="7990658711962795124">"Fleiri valkostir"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Aukið öryggi með aðgangslyklum"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Með aðgangslyklum þarftu hvorki að búa til né muna flókin aðgangsorð"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Aðgangslyklar eru dulkóðaðir stafrænir lyklar sem þú býrð til með fingrafarinu þínu, andliti eða skjálás."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Þeir eru vistaðir í aðgangsorðastjórnun svo þú getir skráð þig inn í öðrum tækjum"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Veldu hvar þú vilt vista <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Veldu aðgangsorðastjórnun til að vista upplýsingarnar og vera fljótari að skrá þig inn næst"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Viltu búa til aðgangslykil fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Viltu vista aðgangsorð fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Viltu vista innskráningarupplýsingar fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>
<string name="password" msgid="6738570945182936667">"aðgangsorð"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"aðgangslyklar"</string>
+ <string name="passwords" msgid="5419394230391253816">"aðgangsorð"</string>
<string name="sign_ins" msgid="4710739369149469208">"innskráningar"</string>
<string name="sign_in_info" msgid="2627704710674232328">"innskráningarupplýsingar"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Vista <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> í"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Viltu búa til aðgangslykil í öðru tæki?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Nota <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> fyrir allar innskráningar?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Þessi aðgangsorðastjórnun vistar aðgangsorð og aðgangslykla til að auðvelda þér að skrá þig inn"</string>
<string name="set_as_default" msgid="4415328591568654603">"Stilla sem sjálfgefið"</string>
<string name="use_once" msgid="9027366575315399714">"Nota einu sinni"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> aðgangsorð • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> aðgangslyklar"</string>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index 0707256..c28659b 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Annulla"</string>
<string name="string_continue" msgid="1346732695941131882">"Continua"</string>
<string name="string_more_options" msgid="7990658711962795124">"Altre opzioni"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Scopri di più"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Più al sicuro con le passkey"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Con le passkey non è necessario creare o ricordare password complesse"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Le passkey sono chiavi digitali criptate che crei usando la tua impronta, il tuo volto o il blocco schermo"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Vengono salvate in un gestore delle password, così potrai accedere su altri dispositivi"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Scopri di più sulle passkey"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Tecnologia senza password"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Le passkey ti consentono di accedere senza usare le password. Devi soltanto usare la tua impronta, il riconoscimento del volto, il tuo PIN o la tua sequenza per verificare la tua identità e creare una passkey."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Crittografia a chiave pubblica"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Basate su standard FIDO Alliance (che include Google, Apple, Microsoft e non solo) e W3C, le passkey usano coppie di chiavi di crittografia. Diversamente dal nome utente e dalla stringa di caratteri usata per le password, per un\'app o un sito web viene creata una coppia di chiavi (privata e pubblica). La chiave privata viene memorizzata in sicurezza sul dispositivo o nel gestore delle password e conferma la tua identità. La chiave pubblica viene condivisa con il server dell\'app o del sito. Con chiavi corrispondenti puoi registrarti e accedere subito."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Sicurezza degli account migliorata"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Ogni chiave è collegata in modo esclusivo all\'app o al sito web per cui è stata creata, quindi non puoi mai accedere a un\'app o un sito web fraudolenti per sbaglio. Inoltre, le compromissioni diventano molto più difficili perché i server conservano soltanto le chiavi pubbliche."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Transizione senza interruzioni"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Mentre ci dirigiamo verso un futuro senza password, queste ultime saranno ancora disponibili insieme alle passkey."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Scegli dove salvare: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Seleziona un gestore delle password per salvare i tuoi dati e accedere più velocemente la prossima volta"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vuoi creare una passkey per <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vuoi salvare la password di <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vuoi salvare i dati di accesso di <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"passkey"</string>
+ <string name="passwords" msgid="5419394230391253816">"password"</string>
<string name="sign_ins" msgid="4710739369149469208">"accessi"</string>
<string name="sign_in_info" msgid="2627704710674232328">"dati di accesso"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Salva <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> in"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Creare la passkey in un altro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vuoi usare <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per tutti gli accessi?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Questo gestore delle password archivierà le password e le passkey per aiutarti ad accedere facilmente"</string>
<string name="set_as_default" msgid="4415328591568654603">"Imposta come valore predefinito"</string>
<string name="use_once" msgid="9027366575315399714">"Usa una volta"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> password • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index be1af3b..1637a94 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"ביטול"</string>
<string name="string_continue" msgid="1346732695941131882">"המשך"</string>
<string name="string_more_options" msgid="7990658711962795124">"אפשרויות נוספות"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"בטוח יותר להשתמש במפתחות גישה"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"עם מפתחות הגישה לא צריך יותר ליצור או לזכור סיסמאות מורכבות"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"מפתחות גישה הם מפתחות דיגיטליים מוצפנים שניתן ליצור באמצעות טביעת האצבע, זיהוי הפנים או נעילת המסך"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"מפתחות הגישה והסיסמאות נשמרים במנהל הסיסמאות כך שניתן להיכנס לחשבון במכשירים אחרים"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"בחירת המקום לשמירה של <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"אפשר לבחור באחד משירותי ניהול הסיסמאות כדי לשמור את הפרטים ולהיכנס לחשבון מהר יותר בפעם הבאה"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ליצור מפתח גישה ל-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index 9bdb9b0..3aab2e9f 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"キャンセル"</string>
<string name="string_continue" msgid="1346732695941131882">"続行"</string>
<string name="string_more_options" msgid="7990658711962795124">"その他のオプション"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"詳細"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"パスキーでより安全に"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"パスキーがあれば、複雑なパスワードを作成したり覚えたりする必要はありません"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"パスキーは、指紋認証、顔認証、または画面ロックを使って作成される暗号化されたデジタルキーです"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"パスワード マネージャーに保存され、他のデバイスでもログインできます"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"パスキーの詳細"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"パスワードレス テクノロジー"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"パスキーを利用すると、ログインにパスワードは必要なくなります。指紋認証、顔認証、PIN を使用するか、パターンをスワイプするだけで、本人確認とパスキーの作成を行えます。"</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"公開鍵暗号"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO アライアンス(Google、Apple、Microsoft などで構成)と W3C 標準に基づき、パスキーでは暗号鍵ペアを使用します。ユーザー名や、パスワードに使う文字列と異なり、アプリやウェブサイトに対して秘密 / 公開鍵ペアが作成されます。秘密鍵はデバイスまたはパスワード マネージャーに安全に保存され、この鍵で本人確認を行います。公開鍵はアプリまたはウェブサイトのサーバーと共有されます。対応する鍵を使うことで、すばやく登録してログインできます。"</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"アカウントのセキュリティを強化"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"作成された各鍵は、対象となるアプリまたはウェブサイトのみとリンクされるため、間違って不正なアプリやウェブサイトにログインすることはありません。さらに、公開鍵はサーバーのみに保存されるため、ハッキングのリスクも大幅に抑えられます。"</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"シームレスな移行"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"将来的にパスワードレスに移行するにあたり、パスワードもパスキーと並行して引き続きご利用いただけます。"</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> の保存先の選択"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"パスワード マネージャーを選択して情報を保存しておくと、次回からすばやくログインできます"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> のパスキーを作成しますか?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> のパスワードを保存しますか?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> のログイン情報を保存しますか?"</string>
<string name="passkey" msgid="632353688396759522">"パスキー"</string>
<string name="password" msgid="6738570945182936667">"パスワード"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"パスキー"</string>
+ <string name="passwords" msgid="5419394230391253816">"パスワード"</string>
<string name="sign_ins" msgid="4710739369149469208">"ログイン"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ログイン情報"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>の保存先"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"別のデバイスにパスキーを作成しますか?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ログインのたびに <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> を使用しますか?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"このパスワード マネージャーに、パスワードやパスキーが保存され、簡単にログインできるようになります"</string>
<string name="set_as_default" msgid="4415328591568654603">"デフォルトに設定"</string>
<string name="use_once" msgid="9027366575315399714">"1 回使用"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 件のパスワード • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 件のパスキー"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index 5b8398a..ee94b7e 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"გაუქმება"</string>
<string name="string_continue" msgid="1346732695941131882">"გაგრძელება"</string>
<string name="string_more_options" msgid="7990658711962795124">"სხვა ვარიანტები"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"შეიტყვეთ მეტი"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"უფრო უსაფრთხოა წვდომის გასაღების შემთხვევაში"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"წვდომის გასაღებების დახმარებით აღარ მოგიწევთ რთული პაროლების შექმნა და დამახსოვრება"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"წვდომის გასაღებები დაშიფრული ციფრული გასაღებებია, რომლებსაც თქვენი თითის ანაბეჭდით, სახით ან ეკრანის დაბლოკვით ქმნით"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ისინი შეინახება პაროლების მმართველში, რათა სხვა მოწყობილობებიდან შესვლაც შეძლოთ"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"დამატებითი ინფორმაცია წვდომის გასაღებების შესახებ"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"უპაროლო ტექნოლოგია"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"წვდომის გასაღებები საშუალებას გაძლევთ, სისტემაში შეხვიდეთ პაროლის გარეშე. უბრალოდ, ვინაობის დასადასტურებლად და წვდომის გასაღების შესაქმნელად უნდა გამოიყენოთ თითის ანაბეჭდი, სახით ამოცნობა, PIN-კოდი, ან განბლოკვის გრაფიკული გასაღები."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"საჯარო გასაღების კრიპტოგრაფია"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO-ს ალიანსისა (Google, Apple, Microsoft და ა.შ.) და W3C-ის სტანდარტების შესაბამისად, წვდომის გასაღებები იყენებს კრიპტოგრაფიულ გასაღებების წყვილს. მომხ. სახ. და სიმბ. სტრიქ. განსხვავებით, რომელთაც პაროლ. ვიყენებთ, რამდენიმე პირადი/საჯარო გას. იქმნება აპის ან ვებსაიტისთვის. პირადი გასაღები უსაფრთხოდ ინახება მოწყობილობაზე ან პაროლ. მმართველში და ის ადასტურებს თქვენს ვინაობას. საჯარო გას. ზიარდება აპისა და ვებ. სერვერის მეშვეობით. შესაბ. გასაღებებით შეგიძლიათ მაშინვე დარეგისტ. და სისტ. შეხვიდეთ."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"ანგარიშის გაუმჯობესებული უსაფრთხოება"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"თითოეული გასაღები დაკავშირებულია მხოლოდ აპთან ან ვებსაიტთან, რომელთათვისაც ის შეიქმნა, ამიტომაც შემთხვევით ვერასდროს შეხვალთ თაღლითურ აპში თუ ვებსაიტზე. ამასთანავე, სერვერები ინახავს მხოლოდ საჯარო გასაღებებს, რაც ართულებს გატეხვის ალბათობას."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"დაუბრკოლებელი გადასვლა"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"უპაროლო მომავალში პაროლები კვლავ ხელმისაწვდომი იქნება, წვდომის გასაღებებთან ერთად."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"აირჩიეთ სად შეინახოთ თქვენი <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"აირჩიეთ პაროლების მმართველი თქვენი ინფორმაციის შესანახად, რომ მომავალში უფრო სწრაფად შეხვიდეთ."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"შექმნით წვდომის გასაღებს <xliff:g id="APPNAME">%1$s</xliff:g> აპისთვის?"</string>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index bf58b21..88c3cb6 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Бас тарту"</string>
<string name="string_continue" msgid="1346732695941131882">"Жалғастыру"</string>
<string name="string_more_options" msgid="7990658711962795124">"Басқа опциялар"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Кіру кілттерімен қауіпсіздеу"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Кіру кілттері бар кезде күрделі құпия сөздер жасаудың немесе оларды есте сақтаудың қажеті жоқ."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Кіру кілттері — саусақ ізі, бет не экран құлпы арқылы жасалатын шифрланған цифрлық кілттер."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Олар құпия сөз менеджеріне сақталады. Соның арқасында басқа құрылғылардан кіре аласыз."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> қайда сақталатынын таңдаңыз"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Мәліметіңізді сақтап, келесіде жылдам кіру үшін құпия сөз менеджерін таңдаңыз."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін кіру кілтін жасау керек пе?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін құпия сөзді сақтау керек пе?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін кіру мәліметін сақтау керек пе?"</string>
<string name="passkey" msgid="632353688396759522">"кіру кілті"</string>
<string name="password" msgid="6738570945182936667">"құпия сөз"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"Кіру кілттері"</string>
+ <string name="passwords" msgid="5419394230391253816">"Құпия сөздер"</string>
<string name="sign_ins" msgid="4710739369149469208">"кіру әрекеттері"</string>
<string name="sign_in_info" msgid="2627704710674232328">"кіру мәліметі"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> тіркелу дерегін сақтау орны:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Кіру кілтін басқа құрылғыда жасау керек пе?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Барлық кіру әрекеті үшін <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> пайдаланылсын ба?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Аккаунтқа кіру оңай болуы үшін, құпия сөз менеджері құпия сөздер мен кіру кілттерін сақтайды."</string>
<string name="set_as_default" msgid="4415328591568654603">"Әдепкі етіп орнату"</string>
<string name="use_once" msgid="9027366575315399714">"Бір рет пайдалану"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> құпия сөз • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кіру кілті"</string>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index 1966aa1..f40ddfb 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"បោះបង់"</string>
<string name="string_continue" msgid="1346732695941131882">"បន្ត"</string>
<string name="string_more_options" msgid="7990658711962795124">"ជម្រើសច្រើនទៀត"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"កាន់តែមានសុវត្ថិភាពដោយប្រើកូដសម្ងាត់"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"តាមរយៈកូដសម្ងាត់ អ្នកមិនចាំបាច់បង្កើត ឬចងចាំពាក្យសម្ងាត់ស្មុគស្មាញនោះទេ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"កូដសម្ងាត់ត្រូវបានអ៊ីនគ្រីបឃីឌីជីថលដែលអ្នកបង្កើតដោយប្រើស្នាមម្រាមដៃ មុខ ឬចាក់សោអេក្រង់របស់អ្នក"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"កូដសម្ងាត់ត្រូវបានរក្សាទុកទៅក្នុងកម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ ដូច្នេះអ្នកអាចចូលនៅលើឧបករណ៍ផ្សេងទៀត"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"ជ្រើសរើសកន្លែងដែលត្រូវរក្សាទុក<xliff:g id="CREATETYPES">%1$s</xliff:g>របស់អ្នក"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ជ្រើសរើសកម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ ដើម្បីរក្សាទុកព័ត៌មានរបស់អ្នក និងចូលគណនីបានកាន់តែរហ័សនៅពេលលើកក្រោយ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"បង្កើតកូដសម្ងាត់សម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"រក្សាទុកពាក្យសម្ងាត់សម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"រក្សាទុកព័ត៌មានអំពីការចូលគណនីសម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
<string name="passkey" msgid="632353688396759522">"កូដសម្ងាត់"</string>
<string name="password" msgid="6738570945182936667">"ពាក្យសម្ងាត់"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"កូដសម្ងាត់"</string>
+ <string name="passwords" msgid="5419394230391253816">"ពាក្យសម្ងាត់"</string>
<string name="sign_ins" msgid="4710739369149469208">"ការចូលគណនី"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ព័ត៌មានអំពីការចូលគណនី"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"រក្សាទុក <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ទៅកាន់"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"បង្កើតកូដសម្ងាត់នៅក្នុងឧបករណ៍ផ្សេងទៀតឬ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ប្រើ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> សម្រាប់ការចូលគណនីទាំងអស់របស់អ្នកឬ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់នេះនឹងរក្សាទុកពាក្យសម្ងាត់ និងកូដសម្ងាត់របស់អ្នក ដើម្បីជួយឱ្យអ្នកចូលគណនីបានយ៉ាងងាយស្រួល"</string>
<string name="set_as_default" msgid="4415328591568654603">"កំណត់ជាលំនាំដើម"</string>
<string name="use_once" msgid="9027366575315399714">"ប្រើម្ដង"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"ពាក្យសម្ងាត់ <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • កូដសម្ងាត់<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index cfc1098..cbc9a26 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"ರದ್ದುಗೊಳಿಸಿ"</string>
<string name="string_continue" msgid="1346732695941131882">"ಮುಂದುವರಿಸಿ"</string>
<string name="string_more_options" msgid="7990658711962795124">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"ಪಾಸ್ಕೀಗಳೊಂದಿಗೆ ಸುರಕ್ಷಿತವಾಗಿರುತ್ತವೆ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ಪಾಸ್ಕೀಗಳ ಮೂಲಕ, ನೀವು ಕ್ಲಿಷ್ಟ ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ರಚಿಸುವ ಅಥವಾ ನೆನಪಿಟ್ಟುಕೊಳ್ಳುವ ಅಗತ್ಯವಿಲ್ಲ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ಪಾಸ್ಕೀಗಳು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್, ಫೇಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು ರಚಿಸುವ ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಡಿಜಿಟಲ್ ಕೀಗಳಾಗಿವೆ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ಅವುಗಳನ್ನು ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಉಳಿಸಲಾಗಿದೆ, ಹಾಗಾಗಿ ನೀವು ಇತರ ಸಾಧನಗಳಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"ಪಾಸ್ಕೀಗಳ ಕುರಿತು ಇನ್ನಷ್ಟು"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"ಪಾಸ್ವರ್ಡ್ ರಹಿತ ತಂತ್ರಜ್ಞಾನ"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"ಪಾಸ್ಕೀಗಳು ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ಅವಲಂಬಿಸದೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಅನುಮತಿಸುತ್ತದೆ. ನಿಮ್ಮ ಗುರುತನ್ನು ಪರಿಶೀಲಿಸಲು ಮತ್ತು ಪಾಸ್ಕೀ ರಚಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್, ಮುಖ ಗುರುತಿಸುವಿಕೆ, ಪಿನ್ ಅಥವಾ ಸ್ವೈಪ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು ಬಳಸಬೇಕಾಗುತ್ತದೆ."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"ಸಾರ್ವಜನಿಕ ಕೀ ಕ್ರಿಪ್ಟೋಗ್ರಫಿ"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ಅಲೈಯನ್ಸ್ (ಇದು Google, Apple, Microsoft ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ) ಮತ್ತು W3C ಮಾನದಂಡಗಳನ್ನು ಆಧರಿಸಿ, ಪಾಸ್ಕೀಗಳು ಕ್ರಿಪ್ಟೋಗ್ರಾಫಿಕ್ ಕೀ ಜೋಡಿಗಳನ್ನು ಬಳಸುತ್ತವೆ. ಪಾಸ್ವರ್ಡ್ಗಳಿಗಾಗಿ ನಾವು ಬಳಸುವ ಬಳಕೆದಾರಹೆಸರು ಮತ್ತು ಅಕ್ಷರಗಳ ಸ್ಟ್ರಿಂಗ್ಗಿಂತ ಭಿನ್ನವಾಗಿ, ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗಾಗಿ ಖಾಸಗಿ-ಸಾರ್ವಜನಿಕ ಕೀ ಜೋಡಿಯನ್ನು ರಚಿಸಲಾಗಿದೆ. ಖಾಸಗಿ ಕೀ ಅನ್ನು ನಿಮ್ಮ ಸಾಧನ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಸುರಕ್ಷಿತವಾಗಿ ಸಂಗ್ರಹಿಸಲಾಗಿದೆ ಮತ್ತು ಅದು ನಿಮ್ಮ ಗುರುತನ್ನು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಸಾರ್ವಜನಿಕ ಕೀ ಅನ್ನು ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ ಸರ್ವರ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗಿದೆ. ಅನುಗುಣವಾದ ಕೀ ಮೂಲಕ, ನೀವು ತಕ್ಷಣ ನೋಂದಾಯಿಸಬಹುದು ಮತ್ತು ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"ಸುಧಾರಿತ ಖಾತೆಯ ಭದ್ರತೆ"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"ಪ್ರತಿಯೊಂದು ಕೀ ಅವುಗಳನ್ನು ರಚಿಸಲಾದ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ನ ಜೊತೆಗೆ ಪ್ರತ್ಯೇಕವಾಗಿ ಲಿಂಕ್ ಮಾಡಲಾಗಿದೆ, ಆದ್ದರಿಂದ ನೀವು ಎಂದಿಗೂ ತಪ್ಪಾಗಿ ವಂಚನೆಯ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಜೊತೆಗೆ, ಸರ್ವರ್ಗಳು ಮಾತ್ರ ಸಾರ್ವಜನಿಕ ಕೀಗಳನ್ನು ಇಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ, ಹ್ಯಾಕಿಂಗ್ ಮಾಡುವುದು ತುಂಬಾ ಕಷ್ಟಕರವಾಗಿದೆ."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"ಅಡಚಣೆರಹಿತ ಪರಿವರ್ತನೆ"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"ನಾವು ಪಾಸ್ವರ್ಡ್ ರಹಿತ ತಂತ್ರಜ್ಞಾನದ ಕಡೆಗೆ ಸಾಗುತ್ತಿರುವಾಗ, ಪಾಸ್ಕೀಗಳ ಜೊತೆಗೆ ಪಾಸ್ವರ್ಡ್ಗಳು ಇನ್ನೂ ಲಭ್ಯವಿರುತ್ತವೆ."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"ನಿಮ್ಮ <xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆರಿಸಿ"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಉಳಿಸಲು ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ ಹಾಗೂ ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಪಾಸ್ಕೀ ಅನ್ನು ರಚಿಸುವುದೇ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಪಾಸ್ವರ್ಡ್ ಉಳಿಸುವುದೇ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಉಳಿಸುವುದೇ?"</string>
<string name="passkey" msgid="632353688396759522">"ಪಾಸ್ಕೀ"</string>
<string name="password" msgid="6738570945182936667">"ಪಾಸ್ವರ್ಡ್"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ಪಾಸ್ಕೀಗಳು"</string>
+ <string name="passwords" msgid="5419394230391253816">"ಪಾಸ್ವರ್ಡ್ಗಳು"</string>
<string name="sign_ins" msgid="4710739369149469208">"ಸೈನ್-ಇನ್ಗಳು"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ಸೈನ್-ಇನ್ ಮಾಹಿತಿ"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"ಇಲ್ಲಿಗೆ <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ಅನ್ನು ಉಳಿಸಿ"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"ಮತ್ತೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್ಕೀಯನ್ನು ರಚಿಸಬೇಕೇ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ನಿಮ್ಮ ಎಲ್ಲಾ ಸೈನ್-ಇನ್ಗಳಿಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸುವುದೇ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"ಈ ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕವು ನಿಮಗೆ ಸುಲಭವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಪಾಸ್ಕೀಗಳನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ"</string>
<string name="set_as_default" msgid="4415328591568654603">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="use_once" msgid="9027366575315399714">"ಒಂದು ಬಾರಿ ಬಳಸಿ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ಪಾಸ್ವರ್ಡ್ಗಳು • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ಪಾಸ್ಕೀಗಳು"</string>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index ed53a6c..beef76f 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"취소"</string>
<string name="string_continue" msgid="1346732695941131882">"계속"</string>
<string name="string_more_options" msgid="7990658711962795124">"옵션 더보기"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"패스키로 더 안전하게"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"패스키를 사용하면 복잡한 비밀번호를 만들거나 기억하지 않아도 됩니다."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"패스키는 지문, 얼굴 또는 화면 잠금으로 생성하는 암호화된 디지털 키입니다."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"비밀번호 관리자에 저장되므로 다른 기기에서 로그인할 수 있습니다."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 저장 위치 선택"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"정보를 저장해서 다음에 더 빠르게 로그인하려면 비밀번호 관리자를 선택하세요."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>의 패스키를 만드시겠습니까?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>의 비밀번호를 저장하시겠습니까?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>의 로그인 정보를 저장하시겠습니까?"</string>
<string name="passkey" msgid="632353688396759522">"패스키"</string>
<string name="password" msgid="6738570945182936667">"비밀번호"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"패스키"</string>
+ <string name="passwords" msgid="5419394230391253816">"비밀번호"</string>
<string name="sign_ins" msgid="4710739369149469208">"로그인 정보"</string>
<string name="sign_in_info" msgid="2627704710674232328">"로그인 정보"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> 저장 위치"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"다른 기기에서 패스키를 만드시겠습니까?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"모든 로그인에 <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>을(를) 사용하시겠습니까?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"이 비밀번호 관리자는 비밀번호와 패스키를 저장하여 사용자가 간편하게 로그인할 수 있도록 돕습니다."</string>
<string name="set_as_default" msgid="4415328591568654603">"기본값으로 설정"</string>
<string name="use_once" msgid="9027366575315399714">"한 번 사용"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"비밀번호 <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>개 • 패스키 <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>개"</string>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index 68ce3c7..6afbb08 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Жок"</string>
<string name="string_continue" msgid="1346732695941131882">"Улантуу"</string>
<string name="string_more_options" msgid="7990658711962795124">"Башка варианттар"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Мүмкүндүк алуу ачкычтары менен коопсузураак болот"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Мүмкүндүк алуу ачкычтары менен татаал сырсөздөрдү түзүп же эстеп калуунун кереги жок"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Мүмкүндүк алуу ачкычтары – манжаңыздын изи, жүзүңүз же экранды кулпулоо функциясы аркылуу түзгөн шифрленген санариптик ачкычтар"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Алар сырсөздөрдү башкаргычка сакталып, аккаунтуңузга башка түзмөктөрдөн кире аласыз"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> кайда сакталарын тандаңыз"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Маалыматыңызды сактоо жана кийинки жолу тезирээк кирүү үчүн сырсөздөрдү башкаргычты тандаңыз"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн мүмкүндүк алуу ачкычын түзөсүзбү?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн сырсөз сакталсынбы?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн кирүү маалыматы сакталсынбы?"</string>
<string name="passkey" msgid="632353688396759522">"мүмкүндүк алуу ачкычы"</string>
<string name="password" msgid="6738570945182936667">"сырсөз"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"мүмкүндүк алуу ачкычтары"</string>
+ <string name="passwords" msgid="5419394230391253816">"сырсөздөр"</string>
<string name="sign_ins" msgid="4710739369149469208">"кирүүлөр"</string>
<string name="sign_in_info" msgid="2627704710674232328">"кирүү маалыматы"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> төмөнкүгө сакталсын:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Мүмкүндүк алуу ачкычы башка түзмөктө түзүлсүнбү?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> бардык аккаунттарга кирүү үчүн колдонулсунбу?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Сырсөздөрүңүздү жана ачкычтарыңызды Сырсөздөрдү башкаргычка сактап коюп, каалаган убакта колдоно берсеңиз болот"</string>
<string name="set_as_default" msgid="4415328591568654603">"Демейки катары коюу"</string>
<string name="use_once" msgid="9027366575315399714">"Бир жолу колдонуу"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> сырсөз • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> мүмкүндүк алуу ачкычы"</string>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index 9814521..b061db4 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"ຍົກເລີກ"</string>
<string name="string_continue" msgid="1346732695941131882">"ສືບຕໍ່"</string>
<string name="string_more_options" msgid="7990658711962795124">"ຕົວເລືອກເພີ່ມເຕີມ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"ປອດໄພຂຶ້ນດ້ວຍກະແຈຜ່ານ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ໂດຍການໃຊ້ກະແຈຜ່ານ, ທ່ານບໍ່ຈຳເປັນຕ້ອງສ້າງ ຫຼື ຈື່ລະຫັດຜ່ານທີ່ຊັບຊ້ອນ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ກະແຈຜ່ານແມ່ນກະແຈດິຈິຕອນທີ່ໄດ້ຖືກເຂົ້າລະຫັດໄວ້ເຊິ່ງທ່ານສ້າງຂຶ້ນໂດຍໃຊ້ລາຍນິ້ວມື, ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ພວກມັນຖືກບັນທຶກໄວ້ຢູ່ໃນຕົວຈັດການລະຫັດຜ່ານ, ດັ່ງນັ້ນທ່ານສາມາດເຂົ້າສູ່ລະບົບຢູ່ອຸປະກອນອື່ນໆໄດ້"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"ເລືອກບ່ອນທີ່ຈະບັນທຶກ <xliff:g id="CREATETYPES">%1$s</xliff:g> ຂອງທ່ານ"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ເລືອກຕົວຈັດການລະຫັດຜ່ານເພື່ອບັນທຶກຂໍ້ມູນຂອງທ່ານ ແລະ ເຂົ້າສູ່ລະບົບໄວຂຶ້ນໃນເທື່ອຕໍ່ໄປ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ສ້າງກະແຈຜ່ານສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"ບັນທຶກລະຫັດຜ່ານສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="passkey" msgid="632353688396759522">"ກະແຈຜ່ານ"</string>
<string name="password" msgid="6738570945182936667">"ລະຫັດຜ່ານ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ກະແຈຜ່ານ"</string>
+ <string name="passwords" msgid="5419394230391253816">"ລະຫັດຜ່ານ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ການເຂົ້າສູ່ລະບົບ"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ຂໍ້ມູນການເຂົ້າສູ່ລະບົບ"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"ບັນທຶກ <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ໃສ່"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"ສ້າງກະແຈຜ່ານໃນອຸປະກອນອື່ນບໍ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ໃຊ້ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ສຳລັບການເຂົ້າສູ່ລະບົບທັງໝົດຂອງທ່ານບໍ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"ຕົວຈັດການລະຫັດຜ່ານນີ້ຈະຈັດເກັບລະຫັດຜ່ານ ແລະ ກະແຈຜ່ານຂອງທ່ານໄວ້ເພື່ອຊ່ວຍໃຫ້ທ່ານເຂົ້າສູ່ລະບົບໄດ້ໂດຍງ່າຍ"</string>
<string name="set_as_default" msgid="4415328591568654603">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ"</string>
<string name="use_once" msgid="9027366575315399714">"ໃຊ້ເທື່ອດຽວ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ລະຫັດຜ່ານ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ກະແຈຜ່ານ"</string>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index 5ec68bb..4197e14 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Atšaukti"</string>
<string name="string_continue" msgid="1346732695941131882">"Tęsti"</string>
<string name="string_more_options" msgid="7990658711962795124">"Daugiau parinkčių"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Sužinokite daugiau"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Saugiau naudojant slaptažodžius"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Naudojant „passkey“ nereikės kurti ir prisiminti sudėtingų slaptažodžių"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"„Passkey“ šifruojami skaitiniais raktais, kuriuos sukuriate naudodami piršto atspaudą, veidą ar ekrano užraktą"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Jie saugomi slaptažodžių tvarkyklėje, kad galėtumėte prisijungti kituose įrenginiuose"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Daugiau apie slaptuosius raktus („passkey“)"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Technologijos be slaptažodžių"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Naudodami slaptuosius raktus galite prisijungti be slaptažodžių. Tiesiog naudokite piršto atspaudą, atpažinimą pagal veidą, PIN kodą arba perbraukiamą atrakinimo piešinį, kad patvirtintumėte tapatybę ir sukurtumėte slaptąjį raktą."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Viešojo rakto kriptografija"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Pagal FIDO aljansą (kuriam priklauso „Google“, „Apple“, „Microsoft“ ir kt.) bei W3C standartus, slaptiesiems raktams naudojamos kriptografinių raktų poros. Priešingai nei naudotojo vardas ir eilutė simbolių, naudojamų slaptažodžiams, privataus ir viešojo raktų pora sukuriama programai ar svetainei. Tapatybę patvirtinantis privatusis raktas saugomas įrenginyje ar Slaptažodžių tvarkyklėje. Viešasis raktas bendrinamas su programos ar svetainės serveriu. Naudodami atitinkamus raktus galite akimirksniu užsiregistruoti ir prisijungti."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Geresnė paskyros sauga"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Kiekvienas raktas išskirtinai susietas su programa ar svetaine, kuriai buvo sukurtas, todėl niekada per klaidą neprisijungsite prie apgavikiškos programos ar svetainės. Be to, viešieji raktai laikomi tik serveriuose, todėl įsilaužti tampa gerokai sudėtingiau."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Sklandus perėjimas"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Kol stengiamės padaryti, kad ateityje nereikėtų naudoti slaptažodžių, jie vis dar bus pasiekiami kartu su slaptaisiais raktais."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Pasirinkite, kur išsaugoti „<xliff:g id="CREATETYPES">%1$s</xliff:g>“"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Pasirinkite slaptažodžių tvarkyklę, kurią naudodami galėsite išsaugoti informaciją ir kitą kartą prisijungti greičiau"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Sukurti „passkey“, skirtą „<xliff:g id="APPNAME">%1$s</xliff:g>“?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Išsaugoti „<xliff:g id="APPNAME">%1$s</xliff:g>“ slaptažodį?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Išsaugoti prisijungimo prie „<xliff:g id="APPNAME">%1$s</xliff:g>“ informaciją?"</string>
<string name="passkey" msgid="632353688396759522">"„passkey“"</string>
<string name="password" msgid="6738570945182936667">"slaptažodis"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"passkey"</string>
+ <string name="passwords" msgid="5419394230391253816">"slaptažodžiai"</string>
<string name="sign_ins" msgid="4710739369149469208">"prisijungimo informacija"</string>
<string name="sign_in_info" msgid="2627704710674232328">"prisijungimo informaciją"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Išsaugoti <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Kurti „passkey“ kitame įrenginyje?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> visada prisijungiant?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Šioje slaptažodžių tvarkyklėje bus saugomi jūsų slaptažodžiai ir „passkey“, kad galėtumėte lengvai prisijungti"</string>
<string name="set_as_default" msgid="4415328591568654603">"Nustatyti kaip numatytąjį"</string>
<string name="use_once" msgid="9027366575315399714">"Naudoti vieną kartą"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Slaptažodžių: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • „Passkey“: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index 71ab864..1ba1ef1 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Atcelt"</string>
<string name="string_continue" msgid="1346732695941131882">"Turpināt"</string>
<string name="string_more_options" msgid="7990658711962795124">"Citas opcijas"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Lielāka drošība ar piekļuves atslēgām"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Izmantojot piekļuves atslēgas, nav jāveido vai jāatceras sarežģītas paroles."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Piekļuves atslēgas ir šifrētas digitālas atslēgas, ko varat izveidot, izmantojot pirksta nospiedumu, seju vai ekrāna bloķēšanas informāciju."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Tās tiek saglabātas paroļu pārvaldniekā, lai jūs varētu pierakstīties citās ierīcēs."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Izvēlieties, kur saglabāt savas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Lai saglabātu informāciju un nākamreiz varētu pierakstīties ātrāk, atlasiet paroļu pārvaldnieku."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vai izveidot piekļuves atslēgu lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vai saglabāt paroli lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vai saglabāt pierakstīšanās informāciju lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"piekļuves atslēga"</string>
<string name="password" msgid="6738570945182936667">"parole"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"piekļuves atslēgas"</string>
+ <string name="passwords" msgid="5419394230391253816">"paroles"</string>
<string name="sign_ins" msgid="4710739369149469208">"pierakstīšanās informācija"</string>
<string name="sign_in_info" msgid="2627704710674232328">"pierakstīšanās informācija"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Kur jāsaglabā <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vai izveidot piekļuves atslēgu citā ierīcē?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vai vienmēr izmantot <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>, lai pierakstītos?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Šis paroļu pārvaldnieks glabās jūsu paroles un piekļuves atslēgas, lai atvieglotu pierakstīšanos."</string>
<string name="set_as_default" msgid="4415328591568654603">"Iestatīt kā noklusējumu"</string>
<string name="use_once" msgid="9027366575315399714">"Izmantot vienreiz"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Paroļu skaits: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Piekļuves atslēgu skaits: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index ae7473f..1be7ca5 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Откажи"</string>
<string name="string_continue" msgid="1346732695941131882">"Продолжи"</string>
<string name="string_more_options" msgid="7990658711962795124">"Повеќе опции"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Побезбедно со криптографски клучеви"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Со криптографските клучеви нема потреба да создавате или да помните сложени лозинки"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Криптографските клучеви се шифрирани дигитални клучеви што ги создавате со вашиот отпечаток, лик или заклучување екран"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Се зачувуваат во управник со лозинки за да може да се најавувате на други уреди"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Изберете каде да ги зачувате вашите <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Изберете Password Manager за да ги зачувате вашите податоци и да се најавите побрзо следниот пат"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Да се создаде криптографски клуч за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index 4075e69..aeef052 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"റദ്ദാക്കുക"</string>
<string name="string_continue" msgid="1346732695941131882">"തുടരുക"</string>
<string name="string_more_options" msgid="7990658711962795124">"കൂടുതൽ ഓപ്ഷനുകൾ"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"കൂടുതലറിയുക"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"പാസ്കീകൾ ഉപയോഗിച്ച് സുരക്ഷിതരാകൂ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"പാസ്കീകൾ ഉപയോഗിക്കുമ്പോൾ നിങ്ങൾ സങ്കീർണ്ണമായ പാസ്വേഡുകൾ സൃഷ്ടിക്കുകയോ ഓർമ്മിക്കുകയോ ചെയ്യേണ്ടതില്ല"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ഫിംഗർപ്രിന്റ്, മുഖം അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിച്ച് നിങ്ങൾ സൃഷ്ടിക്കുന്ന എൻക്രിപ്റ്റ് ചെയ്ത ഡിജിറ്റൽ കീകളാണ് പാസ്കീകൾ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"അവ ഒരു പാസ്വേഡ് മാനേജറിൽ സംരക്ഷിക്കുന്നതിനാൽ നിങ്ങൾക്ക് മറ്റ് ഉപകരണങ്ങളിലും സൈൻ ഇൻ ചെയ്യാം"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"പാസ്കീകളെ കുറിച്ച് കൂടുതൽ വിവരങ്ങൾ"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"പാസ്വേഡ് രഹിത സാങ്കേതികവിദ്യ"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"പാസ്വേഡുകളെ ആശ്രയിക്കാതെ സൈൻ ഇൻ ചെയ്യാൻ പാസ്കീകൾ അനുവദിക്കുന്നു. നിങ്ങളുടെ ഐഡന്റിറ്റി പരിശോധിച്ചുറപ്പിച്ച് പാസ്കീ സൃഷ്ടിക്കാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റ്, മുഖം തിരിച്ചറിയൽ, പിൻ അല്ലെങ്കിൽ സ്വൈപ്പ് പാറ്റേൺ മാത്രം ഉപയോഗിച്ചാൽ മതി."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"എല്ലാവർക്കുമായുള്ള കീ ക്രിപ്റ്റോഗ്രഫി"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (Google, Apple, Microsoft എന്നിവയും മറ്റും ഉൾപ്പെടുന്നത്), W3C മാനദണ്ഡ പ്രകാരം, പാസ്കീ, ക്രിപ്റ്റോഗ്രാഫിക് കീ ജോടി ഉപയോഗിക്കുന്നു. പാസ്വേഡിലുള്ള ഉപയോക്തൃനാമം, പ്രതീകം ഇവയ്ക്ക് പകരം, ആപ്പിനോ വെബ്സൈറ്റിനോ വേണ്ടി പ്രൈവറ്റ്-പബ്ലിക് കീ ജോടി സൃഷ്ടിക്കുന്നു. സ്വകാര്യ കീ നിങ്ങളുടെ ഉപകരണത്തിലോ Password Manager-ലോ സംഭരിക്കുന്നു, ഇത് നിങ്ങളുടെ ഐഡന്റിറ്റി സ്ഥിരീകരിക്കുന്നു. എല്ലാവർക്കുമായുള്ള കീ ആപ്പ്/വെബ്സൈറ്റുമായി പങ്കിടുന്നു. അനുബന്ധ കീ ഉപയോഗിച്ച്, ഉടൻ രജിസ്റ്റർ ചെയ്ത് സൈൻ ഇൻ ചെയ്യാം."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"മെച്ചപ്പെടുത്തിയ അക്കൗണ്ട് സുരക്ഷ"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"ഓരോ കീയും ഏത് ആപ്പിന് അല്ലെങ്കിൽ വെബ്സൈറ്റിന് വേണ്ടിയാണോ സൃഷ്ടിച്ചത്, അതുമായി മാത്രം ലിങ്ക് ചെയ്തിരിക്കുന്നു, അതുകൊണ്ട് നിങ്ങൾ ഒരിക്കലും വഞ്ചനാപരമായ ഒരു ആപ്പിലേക്കോ വെബ്സൈറ്റിലേക്കോ അബദ്ധവശാൽ സൈൻ ഇൻ ചെയ്യില്ല. ഇതോടൊപ്പം, സെർവറുകളിൽ എല്ലാവർക്കുമായുള്ള കീകൾ മാത്രം സൂക്ഷിക്കുന്നതിനാൽ ഹാക്ക് ചെയ്യാൻ വളരെ ബുദ്ധിമുട്ടാണ്."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"ആയാസരഹിതമായ മാറ്റം"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"നമ്മൾ പാസ്വേഡ് രഹിത ഭാവിയിലേക്ക് ചുവടുവെച്ചുകൊണ്ടിരിക്കുകയാണ് എങ്കിലും, പാസ്കീകൾക്കൊപ്പം പാസ്വേഡുകൾ തുടർന്നും ലഭ്യമായിരിക്കും."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"നിങ്ങളുടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എവിടെയാണ് സംരക്ഷിക്കേണ്ടതെന്ന് തിരഞ്ഞെടുക്കുക"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"നിങ്ങളുടെ വിവരങ്ങൾ സംരക്ഷിക്കാനും അടുത്ത തവണ വേഗത്തിൽ സൈൻ ഇൻ ചെയ്യാനും ഒരു പാസ്വേഡ് മാനേജർ തിരഞ്ഞെടുക്കുക"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിനായി പാസ്കീ സൃഷ്ടിക്കണോ?"</string>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index 0ac9ce8..309a10b 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Цуцлах"</string>
<string name="string_continue" msgid="1346732695941131882">"Үргэлжлүүлэх"</string>
<string name="string_more_options" msgid="7990658711962795124">"Бусад сонголт"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Passkey-тэй байхад илүү аюулгүй"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Passkey-н тусламжтай та нарийн төвөгтэй нууц үг үүсгэх эсвэл санах шаардлагагүй"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkey нь таны хурууны хээ, царай эсвэл дэлгэцийн түгжээгээ ашиглан үүсгэсэн шифрлэгдсэн дижитал түлхүүр юм"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Тэдгээрийг нууц үгний менежерт хадгалдаг бөгөөд ингэснээр та бусад төхөөрөмжид нэвтрэх боломжтой"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>-г хаана хадгалахаа сонгоно уу"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Мэдээллээ хадгалж, дараагийн удаа илүү хурдан нэвтрэхийн тулд нууц үгний менежерийг сонгоно уу"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>-д passkey үүсгэх үү?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>-н нууц үгийг хадгалах уу?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>-н нэвтрэх мэдээллийг хадгалах уу?"</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"нууц үг"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"нууц үг"</string>
<string name="sign_ins" msgid="4710739369149469208">"нэвтрэлт"</string>
<string name="sign_in_info" msgid="2627704710674232328">"нэвтрэх мэдээлэл"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>-г дараахад хадгалах"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Өөр төхөөрөмжид passkey үүсгэх үү?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-г бүх нэвтрэлтдээ ашиглах уу?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Хялбархан нэвтрэхэд туслахын тулд энэ нууц үгний менежер таны нууц үг болон passkeys-г хадгална"</string>
<string name="set_as_default" msgid="4415328591568654603">"Өгөгдмөлөөр тохируулах"</string>
<string name="use_once" msgid="9027366575315399714">"Нэг удаа ашиглах"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> нууц үг • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index ab69307..fffcf00 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"रद्द करा"</string>
<string name="string_continue" msgid="1346732695941131882">"पुढे सुरू ठेवा"</string>
<string name="string_more_options" msgid="7990658711962795124">"आणखी पर्याय"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकीसह आणखी सुरक्षित"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"पासकीसोबत, तुम्हाला क्लिष्ट पासवर्ड तयार करण्याची किंवा लक्षात ठेवण्याची आवश्यकता नाही"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"पासकी या तुम्ही तुमचे फिंगरप्रिंट, फेस किंवा स्क्रीन लॉक वापरून तयार करता अशा एंक्रिप्ट केलेल्या डिजिटल की आहेत"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"त्या Password Manager मध्ये सेव्ह केलेल्या असतात, जेणेकरून तुम्ही इतर डिव्हाइसवर साइन इन करू शकाल"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"तुमची <xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे सेव्ह करायची ते निवडा"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"तुमची माहिती सेव्ह करण्यासाठी आणि पुढच्या वेळी जलद साइन इन करण्याकरिता Password Manager निवडा"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी पासकी तयार करायची का?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी पासवर्ड सेव्ह करायचा का?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी साइन-इन माहिती सेव्ह करायची का?"</string>
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"पासकी"</string>
+ <string name="passwords" msgid="5419394230391253816">"पासवर्ड"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन-इन"</string>
<string name="sign_in_info" msgid="2627704710674232328">"साइन-इनसंबंधित माहिती"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> येथे सेव्ह करा"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"दुसऱ्या डिव्हाइसमध्ये पासकी तयार करायची का?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"तुमच्या सर्व साइन-इन साठी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>वापरायचे का?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"तुम्हाला सहजरीत्या साइन इन करण्यात मदत करण्यासाठी हा पासवर्ड व्यवस्थापक तुमचे पासवर्ड आणि पासकी स्टोअर करेल"</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफॉल्ट म्हणून सेट करा"</string>
<string name="use_once" msgid="9027366575315399714">"एकदा वापरा"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index d95c3ea..dcc1987 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Batal"</string>
<string name="string_continue" msgid="1346732695941131882">"Teruskan"</string>
<string name="string_more_options" msgid="7990658711962795124">"Lagi pilihan"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Ketahui lebih lanjut"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Lebih selamat dengan kunci laluan"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Anda tidak perlu mencipta atau mengingati kata laluan yang rumit dengan kunci laluan"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Kunci laluan ialah kunci digital disulitkan yang anda cipta menggunakan cap jari, wajah atau kunci skrin anda"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Kunci laluan disimpan pada password manager supaya anda boleh log masuk pada peranti lain"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Lagi tentang kunci laluan"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Teknologi tanpa kata laluan"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Kunci laluan membolehkan anda log masuk tanpa bergantung pada kata laluan. Anda hanya perlu menggunakan cap jari anda, pengecaman wajah, PIN atau corak leret untuk mengesahkan identiti anda dan mencipta kunci laluan."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografi kunci awam"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Berdasarkan standard Perikatan FIDO (termasuk Google, Apple, Microsoft dll) & W3C, kunci laluan menggunakan pasangan kunci kriptografi. Tidak seperti nama pengguna & rentetan aksara yang digunakan untuk kata laluan, pasangan kunci peribadi-umum dicipta untuk apl/laman web. Kunci persendirian akan disimpan dengan selamat pada peranti atau pengurus kata laluan dan ia mengesahkan identiti anda. Kunci awam dikongsi dengan pelayan apl/laman web. Dengan kunci sepadan, anda boleh mendaftar dan log masuk dengan segera."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Keselamatan akaun yang dipertingkatkan"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Setiap kunci dipautkan secara eksklusif dengan apl atau laman web kunci dicipta, jadi anda tidak boleh log masuk ke apl atau laman web penipuan secara tidak sengaja. Selain itu, dengan pelayan yang hanya menyimpan kunci awam, penggodaman menjadi jauh lebih sukar."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Peralihan yang lancar"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Semasa kita bergerak menuju ke arah masa depan tanpa kata laluan, kata laluan masih akan tersedia bersama dengan kunci laluan."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat untuk menyimpan <xliff:g id="CREATETYPES">%1$s</xliff:g> anda"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Pilih Password Manager untuk menyimpan maklumat anda dan log masuk lebih pantas pada kali seterusnya"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Cipta kunci laluan untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Simpan kata laluan untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan maklumat log masuk untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"kunci laluan"</string>
<string name="password" msgid="6738570945182936667">"kata laluan"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"kunci laluan"</string>
+ <string name="passwords" msgid="5419394230391253816">"kata laluan"</string>
<string name="sign_ins" msgid="4710739369149469208">"log masuk"</string>
<string name="sign_in_info" msgid="2627704710674232328">"maklumat log masuk"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Simpan <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> pada"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Cipta kunci laluan dalam peranti lain?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua log masuk anda?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Password Manager ini akan menyimpan kata laluan dan kunci laluan anda untuk membantu anda log masuk dengan mudah"</string>
<string name="set_as_default" msgid="4415328591568654603">"Tetapkan sebagai lalai"</string>
<string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> kata laluan • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> kunci laluan"</string>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index 6630ffa..d4afb28 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"မလုပ်တော့"</string>
<string name="string_continue" msgid="1346732695941131882">"ရှေ့ဆက်ရန်"</string>
<string name="string_more_options" msgid="7990658711962795124">"နောက်ထပ်ရွေးစရာများ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"လျှို့ဝှက်ကီးများဖြင့် ပိုလုံခြုံသည်"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"လျှို့ဝှက်ကီးများဖြင့် ရှုပ်ထွေးသောစကားဝှက်များကို ပြုလုပ်ရန် (သို့) မှတ်မိရန် မလိုပါ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"လျှို့ဝှက်ကီးများမှာ သင်၏လက်ဗွေ၊ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်သုံး၍ ပြုလုပ်ထားသော အသွင်ဝှက်ထားသည့် ဒစ်ဂျစ်တယ်ကီးများ ဖြစ်သည်"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"၎င်းတို့ကို စကားဝှက်မန်နေဂျာတွင် သိမ်းသဖြင့် အခြားစက်များတွင် လက်မှတ်ထိုးဝင်နိုင်ပါသည်"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"သင်၏ <xliff:g id="CREATETYPES">%1$s</xliff:g> သိမ်းရန်နေရာ ရွေးခြင်း"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"သင့်အချက်အလက်သိမ်းပြီး နောက်တစ်ကြိမ်၌ ပိုမိုမြန်ဆန်စွာ လက်မှတ်ထိုးဝင်ရန် စကားဝှက်မန်နေဂျာကို ရွေးပါ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် လျှို့ဝှက်ကီးပြုလုပ်မလား။"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် စကားဝှက်ကို သိမ်းမလား။"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို သိမ်းမလား။"</string>
<string name="passkey" msgid="632353688396759522">"လျှို့ဝှက်ကီး"</string>
<string name="password" msgid="6738570945182936667">"စကားဝှက်"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"လျှို့ဝှက်ကီးများ"</string>
+ <string name="passwords" msgid="5419394230391253816">"စကားဝှက်များ"</string>
<string name="sign_ins" msgid="4710739369149469208">"လက်မှတ်ထိုးဝင်မှုများ"</string>
<string name="sign_in_info" msgid="2627704710674232328">"လက်မှတ်ထိုးဝင်သည့် အချက်အလက်"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> သိမ်းမည့်နေရာ"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"အခြားစက်ပစ္စည်းတွင် လျှို့ဝှက်ကီး ပြုလုပ်မလား။"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"သင်၏လက်မှတ်ထိုးဝင်မှု အားလုံးအတွက် <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> သုံးမလား။"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"သင်အလွယ်တကူ လက်မှတ်ထိုးဝင်နိုင်ရန် ဤစကားဝှက်မန်နေဂျာက စကားဝှက်နှင့် လျှို့ဝှက်ကီးများကို သိမ်းပေးပါမည်"</string>
<string name="set_as_default" msgid="4415328591568654603">"မူရင်းအဖြစ် သတ်မှတ်ရန်"</string>
<string name="use_once" msgid="9027366575315399714">"တစ်ကြိမ်သုံးရန်"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"စကားဝှက် <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ခု • လျှို့ဝှက်ကီး <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ခု"</string>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 34a81e8..8627030 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Avbryt"</string>
<string name="string_continue" msgid="1346732695941131882">"Fortsett"</string>
<string name="string_more_options" msgid="7990658711962795124">"Flere alternativer"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Tryggere med tilgangsnøkler"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Med tilgangsnøkler trenger du ikke å lage eller huske kompliserte passord"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Tilgangsnøkler er krypterte digitale nøkler du oppretter med fingeravtrykket, ansiktet eller skjermlåsen"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"De lagres i et verktøy for passordlagring, slik at du kan logge på andre enheter"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Velg hvor du vil lagre <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Velg et verktøy for passordlagring for å lagre informasjonen din og logge på raskere neste gang"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vil du opprette en tilgangsnøkkel for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vil du lagre passord for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du lagre påloggingsinformasjon for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"tilgangsnøkkel"</string>
<string name="password" msgid="6738570945182936667">"passord"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"tilgangsnøkler"</string>
+ <string name="passwords" msgid="5419394230391253816">"passord"</string>
<string name="sign_ins" msgid="4710739369149469208">"pålogginger"</string>
<string name="sign_in_info" msgid="2627704710674232328">"påloggingsinformasjon"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Lagre <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> i"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vil du opprette en tilgangsnøkkel på en annen enhet?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for alle pålogginger?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Dette verktøyet for passordlagring lagrer passord og tilgangsnøkler, så det blir lett å logge på"</string>
<string name="set_as_default" msgid="4415328591568654603">"Angi som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Bruk én gang"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passord • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> tilgangsnøkler"</string>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index f98ffff9..b8d63e1 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"रद्द गर्नुहोस्"</string>
<string name="string_continue" msgid="1346732695941131882">"जारी राख्नुहोस्"</string>
<string name="string_more_options" msgid="7990658711962795124">"थप विकल्पहरू"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकीका सहायताले सुरक्षित रहनुहोस्"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"तपाईंले पासकी बनाउनुभयो भने तपाईंले जटिल पासवर्ड बनाउनु वा तिनलाई याद गरिराख्नु पर्दैन"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"पासकी भनेको तपाईंले आफ्नो फिंगरप्रिन्ट, अनुहार वा स्क्रिन लक प्रयोग गरेर बनाएको इन्क्रिप्ट गरिएको डिजिटल की हो"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"तपाईं अन्य डिभाइसहरूमा साइन इन गर्न सक्नुहोस् भन्नाका लागि तिनलाई पासवर्ड म्यानेजरमा सेभ गरिन्छन्"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"तपाईं आफ्ना <xliff:g id="CREATETYPES">%1$s</xliff:g> कहाँ सेभ गर्न चाहनुहुन्छ भन्ने कुरा छनौट गर्नुहोस्"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"कुनै पासवर्ड म्यानेजरमा आफ्नो जानकारी सेभ गरी अर्को टपक अझ छिटो साइन एन गर्नुहोस्"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासकी बनाउने हो?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासवर्ड सेभ गर्ने हो?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> मा साइन गर्न प्रयोग गरिनु पर्ने जानकारी सेभ गर्ने हो?"</string>
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"पासकीहरू"</string>
+ <string name="passwords" msgid="5419394230391253816">"पासवर्डहरू"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन इनसम्बन्धी जानकारी"</string>
<string name="sign_in_info" msgid="2627704710674232328">"साइन इन गर्न प्रयोग गरिने जानकारी"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> यहाँ सेभ गर्नुहोस्:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"अर्को डिभाइसमा पासकी बनाउने हो?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"तपाईंले साइन इन गर्ने सबै डिभाइसहरूमा <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> प्रयोग गर्ने हो?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"तपाईं सजिलैसँग साइन इन गर्न सक्नुहोस् भन्नाका लागि यो पासवर्ड म्यानेजरले तपाईंका पासवर्ड र पासकीहरू सेभ गर्छ"</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफल्ट जानकारीका रूपमा सेट गर्नुहोस्"</string>
<string name="use_once" msgid="9027366575315399714">"एक पटक प्रयोग गर्नुहोस्"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> वटा पासवर्ड • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> वटा पासकी"</string>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index 6bc731b..adea5a3 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Annuleren"</string>
<string name="string_continue" msgid="1346732695941131882">"Doorgaan"</string>
<string name="string_more_options" msgid="7990658711962795124">"Meer opties"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Meer informatie"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Veiliger met toegangssleutels"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Met toegangssleutels hoef je geen ingewikkelde wachtwoorden te maken of te onthouden"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Toegangssleutels zijn versleutelde digitale sleutels die je maakt met je vingerafdruk, gezicht of schermvergrendeling"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ze worden opgeslagen in een wachtwoordmanager zodat je op andere apparaten kunt inloggen"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Meer informatie over toegangssleutels"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Wachtwoordloze technologie"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Met een toegangssleutel heb je geen wachtwoord meer nodig om in te loggen. Als je op deze manier wilt inloggen, moet je je identiteit bevestigen met je vingerafdruk, gezichtsherkenning, pincode of swipepatroon en een toegangssleutel maken."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptografie met openbare sleutels"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Toegangssleutels maken gebruik van cryptografische sleutelparen in overeenstemming met de FIDO Alliance (waartoe onder andere Google, Apple en Microsoft behoren) en W3C-standaarden. Anders dan de combinatie van gebruikersnaam en de tekenreeks die het wachtwoord vormt, wordt bij toegangssleutels voor elke app of website een privé/openbaar sleutelpaar gemaakt. De privésleutel wordt beveiligd opgeslagen op je apparaat of in de wachtwoordmanager om je identiteit te bevestigen. De openbare sleutel wordt gedeeld met de server van de app of website. Als de sleutels overeenkomen, kun je je meteen registreren en inloggen."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Verbeterde accountbeveiliging"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Elke sleutel is exclusief gekoppeld aan de app of website waarvoor deze is gemaakt. Je kunt dus nooit per ongeluk inloggen bij een bedrieglijke app of website. Bovendien bewaren servers alleen openbare sleutels, wat hacken een stuk lastiger maakt."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Naadloze overgang"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"We zijn op weg naar een wachtwoordloze toekomst, maar naast toegangssleutels kun je nog steeds gebruikmaken van wachtwoorden."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Kies waar je je <xliff:g id="CREATETYPES">%1$s</xliff:g> wilt opslaan"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selecteer een wachtwoordmanager om je informatie op te slaan en de volgende keer sneller in te loggen"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Toegangssleutel maken voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Wachtwoord opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Inloggegevens opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"toegangssleutel"</string>
<string name="password" msgid="6738570945182936667">"wachtwoord"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"toegangssleutels"</string>
+ <string name="passwords" msgid="5419394230391253816">"wachtwoorden"</string>
<string name="sign_ins" msgid="4710739369149469208">"inloggegevens"</string>
<string name="sign_in_info" msgid="2627704710674232328">"inloggegevens"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> opslaan in"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Toegangssleutel maken op een ander apparaat?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> elke keer gebruiken als je inlogt?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Deze wachtwoordmanager slaat je wachtwoorden en toegangssleutels op zodat je makkelijk kunt inloggen"</string>
<string name="set_as_default" msgid="4415328591568654603">"Instellen als standaard"</string>
<string name="use_once" msgid="9027366575315399714">"Eén keer gebruiken"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wachtwoorden • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> toegangssleutels"</string>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index f2655c8..6d8af5f 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="string_continue" msgid="1346732695941131882">"ଜାରି ରଖନ୍ତୁ"</string>
<string name="string_more_options" msgid="7990658711962795124">"ଅଧିକ ବିକଳ୍ପ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"ପାସକୀ ସହ ଅଧିକ ସୁରକ୍ଷିତ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ପାସକୀଗୁଡ଼ିକ ସହ ଆପଣଙ୍କୁ ଜଟିଳ ପାସୱାର୍ଡଗୁଡ଼ିକ ତିଆରି କରିବା କିମ୍ବା ମନେରଖିବାର ଆବଶ୍ୟକତା ନାହିଁ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ପାସକୀଗୁଡ଼ିକ ହେଉଛି ଆପଣ ଆପଣଙ୍କ ଟିପଚିହ୍ନ, ଫେସ କିମ୍ବା ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରି ତିଆରି କରୁଥିବା ଏକକ୍ରିପ୍ଟ କରାଯାଇଥିବା ଡିଜିଟାଲ କୀ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ସେଗୁଡ଼ିକୁ ଏକ Password Managerରେ ସେଭ କରାଯାଏ, ଯାହା ଫଳରେ ଆପଣ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକରେ ସାଇନ ଇନ କରିପାରିବେ"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"ଆପଣଙ୍କ <xliff:g id="CREATETYPES">%1$s</xliff:g>କୁ କେଉଁଠାରେ ସେଭ କରିବେ ତାହା ବାଛନ୍ତୁ"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ଆପଣଙ୍କ ସୂଚନା ସେଭ କରି ପରବର୍ତ୍ତୀ ସମୟରେ ଶୀଘ୍ର ସାଇନ ଇନ କରିବା ପାଇଁ ଏକ Password Manager ଚୟନ କରନ୍ତୁ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ପାସକୀ ତିଆରି କରିବେ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ପାସୱାର୍ଡ ସେଭ କରିବେ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ସାଇନ-ଇନର ସୂଚନା ସେଭ କରିବେ?"</string>
<string name="passkey" msgid="632353688396759522">"ପାସକୀ"</string>
<string name="password" msgid="6738570945182936667">"ପାସୱାର୍ଡ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ପାସକୀଗୁଡ଼ିକ"</string>
+ <string name="passwords" msgid="5419394230391253816">"ପାସୱାର୍ଡଗୁଡ଼ିକ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ସାଇନ-ଇନ"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ସାଇନ-ଇନ ସୂଚନା"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>କୁ ଏଥିରେ ସେଭ କରନ୍ତୁ"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ପାସକୀ ତିଆରି କରିବେ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ଆପଣଙ୍କ ସମସ୍ତ ସାଇନ-ଇନ ପାଇଁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବେ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"ଏହି Password Manager ସହଜରେ ସାଇନ ଇନ କରିବାରେ ଆପଣଙ୍କୁ ସାହାଯ୍ୟ କରିବା ପାଇଁ ଆପଣଙ୍କ ପାସୱାର୍ଡ ଏବଂ ପାସକୀଗୁଡ଼ିକୁ ଷ୍ଟୋର କରିବ"</string>
<string name="set_as_default" msgid="4415328591568654603">"ଡିଫଲ୍ଟ ଭାବେ ସେଟ କରନ୍ତୁ"</string>
<string name="use_once" msgid="9027366575315399714">"ଥରେ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ଟି ପାସକୀ"</string>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 824b5db..c77130c 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"ਰੱਦ ਕਰੋ"</string>
<string name="string_continue" msgid="1346732695941131882">"ਜਾਰੀ ਰੱਖੋ"</string>
<string name="string_more_options" msgid="7990658711962795124">"ਹੋਰ ਵਿਕਲਪ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"ਪਾਸਕੀਆਂ ਨਾਲ ਸੁਰੱਖਿਅਤ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ਪਾਸਕੀਆਂ ਨਾਲ, ਤੁਹਾਨੂੰ ਜਟਿਲ ਪਾਸਵਰਡ ਬਣਾਉਣ ਜਾਂ ਯਾਦ ਰੱਖਣ ਦੀ ਲੋੜ ਨਹੀਂ ਹੁੰਦੀ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ਪਾਸਕੀਆਂ ਇਨਕ੍ਰਿਪਟਡ ਡਿਜੀਟਲ ਕੁੰਜੀਆਂ ਹੁੰਦੀਆਂ ਹਨ ਜੋ ਤੁਹਾਡੇ ਵੱਲੋਂ ਤੁਹਾਡੇ ਫਿੰਗਰਪ੍ਰਿੰਟ, ਚਿਹਰੇ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਬਣਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ਉਨ੍ਹਾਂ ਨੂੰ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ \'ਤੇ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਜੋ ਤੁਸੀਂ ਹੋਰ ਡੀਵਾਈਸਾਂ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰ ਸਕੋ"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"ਚੁਣੋ ਕਿ ਆਪਣੇ <xliff:g id="CREATETYPES">%1$s</xliff:g> ਨੂੰ ਕਿੱਥੇ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ਆਪਣੀ ਜਾਣਕਾਰੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਅਤੇ ਅਗਲੀ ਵਾਰ ਤੇਜ਼ੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਚੁਣੋ"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰਨੀ ਹੈ?"</string>
<string name="passkey" msgid="632353688396759522">"ਪਾਸਕੀ"</string>
<string name="password" msgid="6738570945182936667">"ਪਾਸਵਰਡ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ਪਾਸਕੀਆਂ"</string>
+ <string name="passwords" msgid="5419394230391253816">"ਪਾਸਵਰਡ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ਸਾਈਨ-ਇਨਾਂ ਦੀ ਜਾਣਕਾਰੀ"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ਨੂੰ ਇੱਥੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"ਕੀ ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ ਨਾਲ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ਕੀ ਆਪਣੇ ਸਾਰੇ ਸਾਈਨ-ਇਨਾਂ ਲਈ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"ਇਹ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਆਸਾਨੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਿੱਚ ਤੁਹਾਡੀ ਮਦਦ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਾਸਕੀਆਂ ਨੂੰ ਸਟੋਰ ਕਰੇਗਾ"</string>
<string name="set_as_default" msgid="4415328591568654603">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਜੋਂ ਸੈੱਟ ਕਰੋ"</string>
<string name="use_once" msgid="9027366575315399714">"ਇੱਕ ਵਾਰ ਵਰਤੋ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ਪਾਸਵਰਡ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ਪਾਸਕੀਆਂ"</string>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index 8ba182d..9f857d1 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Anuluj"</string>
<string name="string_continue" msgid="1346732695941131882">"Dalej"</string>
<string name="string_more_options" msgid="7990658711962795124">"Więcej opcji"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Klucze zwiększają Twoje bezpieczeństwo"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Dzięki kluczom nie musisz tworzyć ani zapamiętywać skomplikowanych haseł"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Klucze są szyfrowanymi kluczami cyfrowymi, które tworzysz za pomocą funkcji rozpoznawania odcisku palca lub twarzy bądź blokady ekranu"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Klucze są zapisane w menedżerze haseł, dzięki czemu możesz logować się na innych urządzeniach"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Wybierz, gdzie zapisywać <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Wybierz menedżera haseł, aby zapisywać informacje i logować się szybciej"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Utworzyć klucz dla aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Zapisać hasło do aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Zapisać dane logowania do aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"klucz"</string>
<string name="password" msgid="6738570945182936667">"hasło"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"klucze"</string>
+ <string name="passwords" msgid="5419394230391253816">"hasła"</string>
<string name="sign_ins" msgid="4710739369149469208">"dane logowania"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informacje dotyczące logowania"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Zapisać: <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> w:"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Utworzyć klucz na innym urządzeniu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Używać usługi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> w przypadku wszystkich danych logowania?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Menedżer haseł będzie zapisywał Twoje hasła i klucze, aby ułatwić Ci logowanie"</string>
<string name="set_as_default" msgid="4415328591568654603">"Ustaw jako domyślną"</string>
<string name="use_once" msgid="9027366575315399714">"Użyj raz"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Klucze: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index 7aac738..7deefbb 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Mais opções"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mais segurança com as chaves de acesso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Com as chaves de acesso, você não precisa criar nem se lembrar de senhas complexas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"As chaves de acesso são chaves digitais criptografadas que você cria usando a impressão digital, o rosto ou o bloqueio de tela"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Elas são salvas em um gerenciador de senhas para que você possa fazer login em outros dispositivos"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para o app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index df8477e..6ad17e0 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Mais opções"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Saber mais"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mais segurança com chaves de acesso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Com as chaves de acesso, não precisa de criar nem memorizar palavras-passe complexas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"As chaves de acesso são chaves digitais encriptadas que cria através da sua impressão digital, rosto ou bloqueio de ecrã"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"São guardadas num gestor de palavras-passe para que possa iniciar sessão noutros dispositivos"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Mais acerca das chaves de acesso"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Tecnologia sem palavras-passe"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"As chaves de acesso permitem-lhe iniciar sessão sem depender das palavras-passe. Basta usar a impressão digital, o reconhecimento facial, o PIN ou o padrão de deslize para validar a sua identidade e criar uma chave de acesso."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Criptografia de chaves públicas"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Baseadas na FIDO Alliance e no W3C, as palavras de acesso usam pares de chaves criptográficas. Ao contrário do nome de utilizador e da string de carateres das palavras-passe, cria-se um par de chaves públicas/privadas para a app ou Website. A chave privada é armazenada de forma segura no dispositivo ou gestor de palavras-passe e confirma a identidade. A chave pública é partilhada com o servidor do Website ou app. Com as chaves correspondentes, pode registar-se e iniciar sessão instantaneamente."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Segurança melhorada nas contas"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Cada chave é exclusivamente associada à app ou ao Website para o qual foi criada, por isso, nunca pode iniciar sessão numa app ou num Website fraudulento acidentalmente. Além disso, os servidores só mantêm chaves públicas, o que dificulta a pirataria."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Transição sem complicações"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"À medida que avançamos para um futuro sem palavras-passe, as palavras-passe continuam disponíveis juntamente com as chaves de acesso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde guardar as suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gestor de palavras-passe para guardar as suas informações e iniciar sessão mais rapidamente da próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para a app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index 7aac738..7deefbb 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="7990658711962795124">"Mais opções"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mais segurança com as chaves de acesso"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Com as chaves de acesso, você não precisa criar nem se lembrar de senhas complexas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"As chaves de acesso são chaves digitais criptografadas que você cria usando a impressão digital, o rosto ou o bloqueio de tela"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Elas são salvas em um gerenciador de senhas para que você possa fazer login em outros dispositivos"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para o app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 10ff472..73bddea 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Anulează"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuă"</string>
<string name="string_more_options" msgid="7990658711962795124">"Mai multe opțiuni"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mai în siguranță cu chei de acces"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Dacă folosești chei de acces, nu este nevoie să creezi sau să reții parole complexe"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Cheile de acces sunt chei digitale criptate pe care le creezi folosindu-ți amprenta, fața sau blocarea ecranului"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Acestea sunt salvate într-un manager de parole, ca să te poți conecta pe alte dispozitive"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Alege unde dorești să salvezi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Selectează un manager de parole pentru a salva informațiile și a te conecta mai rapid data viitoare"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Creezi o cheie de acces pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvezi parola pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvezi informațiile de conectare pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"cheie de acces"</string>
<string name="password" msgid="6738570945182936667">"parolă"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"cheile de acces"</string>
+ <string name="passwords" msgid="5419394230391253816">"parolele"</string>
<string name="sign_ins" msgid="4710739369149469208">"date de conectare"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informațiile de conectare"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Salvează <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> în"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Creezi cheia de acces pe alt dispozitiv?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Folosești <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pentru toate conectările?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Managerul de parole îți va stoca parolele și cheile de acces, pentru a te ajuta să te conectezi cu ușurință"</string>
<string name="set_as_default" msgid="4415328591568654603">"Setează ca prestabilite"</string>
<string name="use_once" msgid="9027366575315399714">"Folosește o dată"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parole • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chei de acces"</string>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index 9a0d979..3f12657 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Отмена"</string>
<string name="string_continue" msgid="1346732695941131882">"Продолжить"</string>
<string name="string_more_options" msgid="7990658711962795124">"Ещё"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Подробнее"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Ключи доступа безопаснее"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Благодаря ключам доступа вам не придется создавать или запоминать сложные пароли."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ключ доступа – это зашифрованное цифровое удостоверение, которое создается с использованием отпечатка пальца, функции фейсконтроля или блокировки экрана."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Данные хранятся в менеджере паролей, чтобы вы могли входить в аккаунт на других устройствах."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Подробнее о ключах доступа"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Технология аутентификации без пароля"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Ключи доступа позволяют входить в аккаунт без ввода пароля. Чтобы подтвердить личность и создать ключ доступа, достаточно использовать отпечаток пальца, распознавание по лицу, PIN-код или графический ключ."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Шифрование с помощью открытого ключа"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Согласно стандартам W3C и ассоциации FIDO Alliance (Google, Apple, Microsoft и др.) для создания ключей доступа используются пары криптографических ключей. В приложении или на сайте создается не имя пользователя и пароль, а пара открытого и закрытого ключей. Закрытый ключ хранится на вашем устройстве или в менеджере паролей и нужен для подтверждения личности. Открытый ключ передается приложению или серверу сайта. Подходящие ключи помогают быстро войти в аккаунт или зарегистрироваться."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Повышенная безопасность аккаунта"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Каждый ключ связан только с тем приложением или сайтом, для которого был создан, поэтому вы не сможете по ошибке войти в приложение или на сайт мошенников. Кроме того, на серверах хранятся только открытые ключи, что служит дополнительной защитой от взлома."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Плавный переход"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Хотя движение к будущему без паролей уже началось, их по-прежнему можно будет использовать наряду с ключами доступа."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Укажите, куда нужно сохранить <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Выберите менеджер паролей, чтобы сохранять учетные данные и быстро выполнять вход."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Создать ключ доступа для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Сохранить пароль для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Сохранить учетные данные для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
<string name="passkey" msgid="632353688396759522">"ключ доступа"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ключи доступа"</string>
+ <string name="passwords" msgid="5419394230391253816">"пароли"</string>
<string name="sign_ins" msgid="4710739369149469208">"входы"</string>
<string name="sign_in_info" msgid="2627704710674232328">"учетные данные"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Сохранить <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> в"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Создать ключ доступа на другом устройстве?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Всегда входить с помощью приложения \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"В этом менеджере паролей можно сохранять учетные данные, например ключи доступа, чтобы потом использовать их для быстрого входа."</string>
<string name="set_as_default" msgid="4415328591568654603">"Использовать по умолчанию"</string>
<string name="use_once" msgid="9027366575315399714">"Использовать один раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Пароли (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) и ключи доступа (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index 11a7a38..64038ca 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"අවලංගු කරන්න"</string>
<string name="string_continue" msgid="1346732695941131882">"ඉදිරියට යන්න"</string>
<string name="string_more_options" msgid="7990658711962795124">"තවත් විකල්ප"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"තව දැන ගන්න"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"මුරයතුරු සමග සුරක්ෂිතයි"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"මුරයතුරු සමග, ඔබට සංකීර්ණ මුරපද තැනීමට හෝ මතක තබා ගැනීමට අවශ්ය නොවේ"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"මුරයතුරු යනු ඔබේ ඇඟිලි සලකුණ, මුහුණ, හෝ තිර අගුල භාවිතයෙන් ඔබ තනන සංකේතාත්මක ඩිජිටල් යතුරු වේ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ඒවා මුරපද කළමනාකරුවෙකු වෙත සුරකින බැවින්, ඔබට වෙනත් උපාංග මත පුරනය විය හැක"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"මුරයතුරු ගැන වැඩි විස්තර"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"මුරපද රහිත තාක්ෂණය"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"මුරයතුරු මත විශ්වාසය නොතබා පුරනය වීමට මුරපද ඔබට ඉඩ සලසයි. ඔබට ඔබේ අනන්යතාව තහවුරු කර ගැනීමට සහ මුරයතුරක් සෑදීමට ඔබේ ඇඟිලි සලකුණ, මුහුණු හඳුනාගැනීම, රහස් අංකය, හෝ ස්වයිප් රටාව භාවිත කිරීමට අවශ්ය වේ."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"පොදු යතුරු ගුප්ත කේතනය"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO සන්ධාන (Google, Apple, Microsoft, සහ තවත් ඒවා ඇතුළත්) සහ W3C සම්මත මත පදනම්ව, මුරයතුරු ගුප්ත කේතන යතුරු යුගල භාවිත කරයි. අපි මුරපද සඳහා භාවිත කරන පරිශීලක නාමය සහ අනුලකුණු මෙන් නොව, යෙදුමක් හෝ වෙබ් අඩවියක් සඳහා පෞද්ගලික පොදු යතුරු යුගලයක් සාදනු ලැබේ. පෞද්ගලික යතුර ආරක්ෂිතව ඔබේ උපාංගයේ හෝ මුරපද කළමනාකරු මත ගබඩා කර ඇති අතර එය ඔබේ අනන්යතාව තහවුරු කරයි. යෙදුම හෝ වෙබ් අඩවි සේවාදායකය සමග පොදු යතුර බෙදාගෙන ඇත. අනුරූප යතුරු සමග, ඔබට ක්ෂණිකව ලියාපදිංචි වී පුරනය විය හැක."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"වැඩිදියුණු කළ ගිණුම් ආරක්ෂාව"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"සෑම යතුරක්ම ඒවා නිර්මාණය කරන ලද යෙදුම හෝ වෙබ් අඩවිය සමග අනන්ය වශයෙන්ම සම්බන්ධ කර ඇත, එබැවින් ඔබට කිසි විටෙක වැරදීමකින් වංචනික යෙදුමකට හෝ වෙබ් අඩවියකට පුරනය විය නොහැක. ඊට අමතරව, සේවාදායකයින් පොදු යතුරු තබා ගැනීමත් සමග, අනවසරයෙන් ඇතුළුවීම වඩා දුෂ්කරය."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"බාධාවකින් තොර සංක්රමණය"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"අපි මුරපද රහිත අනාගතයක් කරා ගමන් කරන විට, මුරයතුරු සමග මුරපද තවමත් පවතී."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"ඔබේ <xliff:g id="CREATETYPES">%1$s</xliff:g> සුරැකිය යුතු ස්ථානය තෝරා ගන්න"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"ඔබේ තතු සුරැකීමට සහ මීළඟ වතාවේ වේගයෙන් පුරනය වීමට මුරපද කළමනාකරුවෙකු තෝරන්න"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා මුරයතුර තනන්න ද?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා මුරපදය සුරකින්න ද?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා පුරනය වීමේ තතු සුරකින්න ද?"</string>
<string name="passkey" msgid="632353688396759522">"මුරයතුර"</string>
<string name="password" msgid="6738570945182936667">"මුරපදය"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"මුරයතුරු"</string>
+ <string name="passwords" msgid="5419394230391253816">"මුරපද"</string>
<string name="sign_ins" msgid="4710739369149469208">"පුරනය වීම්"</string>
<string name="sign_in_info" msgid="2627704710674232328">"පුරනය වීමේ තතු"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"වෙත <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> සුරකින්න"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"වෙනත් උපාංගයක මුරයතුර තනන්න ද?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ඔබේ සියලු පුරනය වීම් සඳහා <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> භාවිතා කරන්න ද?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"මෙම මුරපද කළමනාකරු ඔබට පහසුවෙන් පුරනය වීමට උදවු කිරීම සඳහා ඔබේ මුරපද සහ මුරයතුරු ගබඩා කරනු ඇත"</string>
<string name="set_as_default" msgid="4415328591568654603">"පෙරනිමි ලෙස සකසන්න"</string>
<string name="use_once" msgid="9027366575315399714">"වරක් භාවිතා කරන්න"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"මුරපද <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ක් • මුරයතුරු <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ක්"</string>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index eba5779..635f0047 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"Zrušiť"</string>
<string name="string_continue" msgid="1346732695941131882">"Pokračovať"</string>
<string name="string_more_options" msgid="7990658711962795124">"Ďalšie možnosti"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"Ďalšie informácie"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Bezpečnejšie s prístupovými kľúčmi"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Ak máte prístupové kľúče, nemusíte vytvárať ani si pamätať zložité heslá"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Prístupové kľúče sú šifrované digitálne kľúče, ktoré môžete vytvoriť odtlačkom prsta, tvárou alebo zámkou obrazovky."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ukladajú sa do správcu hesiel, aby ste sa mohli prihlasovať v iných zariadeniach"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Viac o prístupových kľúčoch"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"Technológia bez hesiel"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Prístupový kľúče vám umožňujú prihlásiť sa bez využitia hesiel. Stačí overiť totožnosť odtlačkom prsta, rozpoznávaním tváre, kódom PIN alebo vzorom potiahnutia a vytvoriť prístupový kľúč."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kryptografia verejných kľúčov"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Prístup. kľúče firiem patriacich do združenia FIDO (zahŕňajúceho Google, Apple, Microsoft a ďalšie) využívajú páry kryptograf. kľúčov a štandardy W3C. Na rozdiel od použív. mena a reťazca znakov využívaných v prípade hesiel sa pár súkr. a verej. kľúča vytvára pre aplikáciu alebo web. Súkr. kľúč sa bezpečne ukladá v zar. či správcovi hesiel a slúži na overenie totožnosti. Verej. kľúč sa zdieľa so serverom danej aplik. alebo webu. Príslušnými kľúčami sa môžete okamžite registrovať a prihlasovať."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Lepšie zabezpečenie účtu"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Každý kľúč je výhradne prepojený s aplikáciou alebo webom, pre ktorý bol vytvorený, takže sa nikdy nemôžete omylom prihlásiť do podvodnej aplikácie alebo na podvodnom webe. Servery navyše uchovávajú iba verejné kľúče, čím podstatne sťažujú hackovanie."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"Plynulý prechod"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Blížime sa k budúcnosti bez hesiel, ale heslá budú popri prístupových kľúčoch stále k dispozícii."</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"Vyberte, kam sa majú ukladať <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správcu hesiel, do ktorého sa budú ukladať vaše údaje, aby ste sa nabudúce mohli rýchlejšie prihlásiť"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Chcete vytvoriť prístupový kľúč pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Chcete uložiť heslo pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Chcete uložiť prihlasovacie údaje pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"prístupový kľúč"</string>
<string name="password" msgid="6738570945182936667">"heslo"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"prístupové kľúče"</string>
+ <string name="passwords" msgid="5419394230391253816">"heslá"</string>
<string name="sign_ins" msgid="4710739369149469208">"prihlasovacie údaje"</string>
<string name="sign_in_info" msgid="2627704710674232328">"prihlasovacie údaje"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Uložiť <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> do"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Chcete vytvoriť prístupový kľúč v inom zariadení?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Chcete pre všetky svoje prihlasovacie údaje použiť <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Tento správca hesiel uchová vaše heslá a prístupové kľúče, aby vám pomohol ľahšie sa prihlasovať"</string>
<string name="set_as_default" msgid="4415328591568654603">"Nastaviť ako predvolené"</string>
<string name="use_once" msgid="9027366575315399714">"Použiť raz"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Počet hesiel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Počet prístupových kľúčov: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 7201f32..a8561f4 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Prekliči"</string>
<string name="string_continue" msgid="1346732695941131882">"Naprej"</string>
<string name="string_more_options" msgid="7990658711962795124">"Več možnosti"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Večja varnost s ključi za dostop"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Po zaslugi ključev za dostop vam ni treba ustvarjati ali si zapomniti zapletenih gesel."</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ključi za dostop so šifrirani digitalni ključi, ki jih ustvarite s prstnim odtisom, obrazom ali načinom zaklepanja zaslona."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Shranjeni so v upravitelju gesel, kar pomeni, da se z njimi lahko prijavite tudi v drugih napravah."</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Izbira mesta za shranjevanje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Izberite upravitelja gesel za shranjevanje podatkov za prijavo, da se boste naslednjič lahko hitreje prijavili."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite ustvariti ključ za dostop do aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Želite shraniti geslo za aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Želite shraniti podatke za prijavo za aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"ključ za dostop"</string>
<string name="password" msgid="6738570945182936667">"geslo"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ključev za dostop"</string>
+ <string name="passwords" msgid="5419394230391253816">"gesel"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
<string name="sign_in_info" msgid="2627704710674232328">"podatkov za prijavo"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Mesto shranjevanja <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Želite ustvariti ključ za dostop v drugi napravi?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite za vse prijave uporabiti »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"V tem upravitelju gesel bodo shranjeni gesla in ključi za dostop, kar vam bo olajšalo prijavo."</string>
<string name="set_as_default" msgid="4415328591568654603">"Nastavi kot privzeto"</string>
<string name="use_once" msgid="9027366575315399714">"Uporabi enkrat"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Št. gesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Št. ključev za dostop: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index 87cc2fe..897450e 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Anulo"</string>
<string name="string_continue" msgid="1346732695941131882">"Vazhdo"</string>
<string name="string_more_options" msgid="7990658711962795124">"Opsione të tjera"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Më e sigurt me çelësat e kalimit"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Me çelësat e kalimit, nuk ka nevojë të krijosh ose të mbash mend fjalëkalime të ndërlikuara"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Çelësat e kalimit kanë çelësa dixhitalë të enkriptuar që ti i krijon duke përdorur gjurmën e gishtit, fytyrën ose kyçjen e ekranit"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ata ruhen te një menaxher fjalëkalimesh, në mënyrë që mund të identifikohesh në pajisje të tjera"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Zgjidh se ku të ruash <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Zgjidh një menaxher fjalëkalimesh për të ruajtur informacionet e tua dhe për t\'u identifikuar më shpejt herën tjetër"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Të krijohet çelësi i kalimit për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Të ruhet fjalëkalimi për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Të ruhen informacionet e identifikimit për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"çelësi i kalimit"</string>
<string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"çelësa kalimi"</string>
+ <string name="passwords" msgid="5419394230391253816">"fjalëkalime"</string>
<string name="sign_ins" msgid="4710739369149469208">"identifikimet"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informacionet e identifikimit"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Ruaj <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> te"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Të krijohet çelës kalimi në një pajisje tjetër?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Të përdoret <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> për të gjitha identifikimet?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ky menaxher i fjalëkalimeve do të ruajë fjalëkalimet dhe çelësat e kalimit për të të ndihmuar të identifikohesh me lehtësi"</string>
<string name="set_as_default" msgid="4415328591568654603">"Cakto si parazgjedhje"</string>
<string name="use_once" msgid="9027366575315399714">"Përdor një herë"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> fjalëkalime • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> çelësa kalimi"</string>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index 80c0537..375d97dc 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Откажи"</string>
<string name="string_continue" msgid="1346732695941131882">"Настави"</string>
<string name="string_more_options" msgid="7990658711962795124">"Још опција"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Безбедније уз приступне кодове"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Уз приступне кодове нема потребе да правите или памтите сложене лозинке"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Приступни кодови су шифровани дигитални кодови које правите помоћу отиска прста, лица или закључавања екрана"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Чувају се у менаџеру лозинки да бисте могли да се пријављујете на другим уређајима"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Одаберите где ћете сачувати ставке <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Изаберите менаџера лозинки да бисте сачували податке и брже се пријавили следећи пут"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Желите да направите приступни кôд за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Желите да сачувате лозинку за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Желите да сачувате податке за пријављивање за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"приступни кôд"</string>
<string name="password" msgid="6738570945182936667">"лозинка"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"приступни кодови"</string>
+ <string name="passwords" msgid="5419394230391253816">"лозинке"</string>
<string name="sign_ins" msgid="4710739369149469208">"пријављивања"</string>
<string name="sign_in_info" msgid="2627704710674232328">"подаци за пријављивање"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Сачувајте ставку<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> у"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Желите да направите приступни кôд на другом уређају?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Желите да за сва пријављивања користите: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Овај менаџер лозинки ће чувати лозинке и приступне кодове да бисте се лако пријављивали"</string>
<string name="set_as_default" msgid="4415328591568654603">"Подеси као подразумевано"</string>
<string name="use_once" msgid="9027366575315399714">"Користи једном"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Приступних кодова:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index ab8c5aa..d1a043d 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Avbryt"</string>
<string name="string_continue" msgid="1346732695941131882">"Fortsätt"</string>
<string name="string_more_options" msgid="7990658711962795124">"Fler alternativ"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Säkrare med nycklar"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Med nycklar behöver du inte skapa eller komma ihop invecklade lösenord"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Nycklar är krypterade digitala nycklar som du skapar med ditt fingeravtryck, ansikte eller skärmlås"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"De sparas i lösenordshanteraren så att du kan logga in på andra enheter"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Välj var du vill spara <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Välj en lösenordshanterare för att spara dina uppgifter och logga in snabbare nästa gång"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vill du skapa en nyckel för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index 1685882..68af50b 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Ghairi"</string>
<string name="string_continue" msgid="1346732695941131882">"Endelea"</string>
<string name="string_more_options" msgid="7990658711962795124">"Chaguo zaidi"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Ni salama ukitumia funguo za siri"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Kwa kutumia funguo za siri, huhitaji kuunda au kukumbuka manenosiri changamano"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Funguo za siri ni funguo dijitali zilizosimbwa kwa njia fiche unazounda kwa kutumia alama yako ya kidole, uso au mbinu ya kufunga skrini"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Vyote huhifadhiwa kwenye kidhibiti cha manenosiri, ili uweze kuingia katika akaunti kwenye vifaa vingine"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Chagua ambako unahifadhi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Chagua kidhibiti cha manenosiri ili uhifadhi taarifa zako na uingie kwenye akaunti kwa urahisi wakati mwingine"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ungependa kuunda ufunguo wa siri kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Ungependa kuhifadhi nenosiri kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ungependa kuhifadhi maelezo ya kuingia katika akaunti kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>
<string name="password" msgid="6738570945182936667">"nenosiri"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"funguo za siri"</string>
+ <string name="passwords" msgid="5419394230391253816">"manenosiri"</string>
<string name="sign_ins" msgid="4710739369149469208">"michakato ya kuingia katika akaunti"</string>
<string name="sign_in_info" msgid="2627704710674232328">"maelezo ya kuingia katika akaunti"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Hifadhi <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> kwenye"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Ungependa kuunda ufunguo wa siri kwenye kifaa kingine?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Ungependa kutumia <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kwa ajili ya michakato yako yote ya kuingia katika akaunti?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Kidhibiti hiki cha manenosiri kitahifadhi manenosiri na funguo zako za siri ili kukusaidia uingie katika akaunti kwa urahisi"</string>
<string name="set_as_default" msgid="4415328591568654603">"Weka iwe chaguomsingi"</string>
<string name="use_once" msgid="9027366575315399714">"Tumia mara moja"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Manenosiri <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • funguo <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> za siri"</string>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index 5c68f66..9857215 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"ரத்துசெய்"</string>
<string name="string_continue" msgid="1346732695941131882">"தொடர்க"</string>
<string name="string_more_options" msgid="7990658711962795124">"கூடுதல் விருப்பங்கள்"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"கடவுச்சாவிகள் மூலம் பாதுகாப்பாக வைத்திருங்கள்"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"கடவுச்சாவிகளைப் பயன்படுத்துவதன் மூலம் கடினமான கடவுச்சொற்களை உருவாக்கவோ நினைவில்கொள்ளவோ தேவையில்லை"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"கடவுச்சாவிகள் என்பவை உங்கள் கைரேகை, முகம் அல்லது திரைப் பூட்டு மூலம் உருவாக்கப்படும் என்க்ரிப்ஷன் செய்யப்பட்ட டிஜிட்டல் சாவிகள் ஆகும்"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"அவை Password Managerரில் சேமிக்கப்பட்டுள்ளதால் நீங்கள் பிற சாதனங்களிலிருந்து உள்நுழையலாம்"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"உங்கள் <xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே சேமிக்கப்பட வேண்டும் என்பதைத் தேர்வுசெய்யுங்கள்"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"உங்கள் தகவல்களைச் சேமித்து அடுத்த முறை விரைவாக உள்நுழைய ஒரு கடவுச்சொல் நிர்வாகியைத் தேர்வுசெய்யுங்கள்"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான கடவுச்சாவியை உருவாக்கவா?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான கடவுச்சொல்லைச் சேமிக்கவா?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான உள்நுழைவு விவரங்களைச் சேமிக்கவா?"</string>
<string name="passkey" msgid="632353688396759522">"கடவுக்குறியீடு"</string>
<string name="password" msgid="6738570945182936667">"கடவுச்சொல்"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"கடவுச்சாவிகள்"</string>
+ <string name="passwords" msgid="5419394230391253816">"கடவுச்சொற்கள்"</string>
<string name="sign_ins" msgid="4710739369149469208">"உள்நுழைவுகள்"</string>
<string name="sign_in_info" msgid="2627704710674232328">"உள்நுழைவு விவரங்கள்"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ஐ இதில் சேமியுங்கள்"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"வேறொரு சாதனத்தில் கடவுச்சாவியை உருவாக்க வேண்டுமா?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"உங்கள் அனைத்து உள்நுழைவுகளுக்கும் <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"இந்தக் கடவுச்சொல் நிர்வாகி உங்கள் கடவுச்சொற்களையும் கடவுச்சாவிகளையும் சேமித்து நீங்கள் எளிதாக உள்நுழைய உதவும்"</string>
<string name="set_as_default" msgid="4415328591568654603">"இயல்பானதாக அமை"</string>
<string name="use_once" msgid="9027366575315399714">"ஒருமுறை பயன்படுத்தவும்"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> கடவுச்சொற்கள் • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> கடவுச்சாவிகள்"</string>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index f428ced..e62bac9 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"రద్దు చేయండి"</string>
<string name="string_continue" msgid="1346732695941131882">"కొనసాగించండి"</string>
<string name="string_more_options" msgid="7990658711962795124">"మరిన్ని ఆప్షన్లు"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"మరింత తెలుసుకోండి"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"పాస్-కీలతో సురక్షితంగా చెల్లించవచ్చు"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"పాస్-కీలతో, మీరు క్లిష్టమైన పాస్వర్డ్లను క్రియేట్ చేయనవసరం లేదు లేదా గుర్తుంచుకోనవసరం లేదు"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"పాస్-కీలు అనేవి మీ వేలిముద్రను, ముఖాన్ని లేదా స్క్రీన్ లాక్ను ఉపయోగించి మీరు క్రియేట్ చేసే ఎన్క్రిప్ట్ చేసిన డిజిటల్ కీలు"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"అవి Password Managerకు సేవ్ చేయబడతాయి, తద్వారా మీరు ఇతర పరికరాలలో సైన్ ఇన్ చేయవచ్చు"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"పాస్-కీల గురించి మరిన్ని వివరాలు"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"పాస్వర్డ్ రహిత టెక్నాలజీ"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"పాస్వర్డ్లపై ఆధారపడకుండా సైన్ ఇన్ చేయడానికి పాస్-కీలు మిమ్మల్ని అనుమతిస్తాయి. మీ గుర్తింపును వెరిఫై చేసి, పాస్-కీని క్రియేట్ చేయడానికి మీరు మీ వేలిముద్ర, ముఖ గుర్తింపు, PIN, లేదా స్వైప్ ఆకృతిని ఉపయోగించాలి."</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"పబ్లిక్ కీ క్రిప్టోగ్రఫీ"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (దీనిలో Google, Apple, Microsoft, మరిన్ని ఉన్నాయి), W3C ప్రమాణాల ప్రకారం, పాస్కీలు క్రిప్టోగ్రాఫిక్ కీల జతలను ఉపయోగిస్తాయి. మనం పాస్వర్డ్ల కోసం ఉపయోగించే యూజర్నేమ్, అక్షరాల స్ట్రింగ్ కాకుండా, యాప్ లేదా సైట్ కోసం ప్రైవేట్-పబ్లిక్ కీల జత సృష్టించబడుతుంది. ప్రైవేట్ కీ మీ డివైజ్/పాస్వర్డ్ మేనేజర్లో సురక్షితంగా స్టోర్ చేయబడుతుంది, ఇది మీ గుర్తింపును నిర్ధారిస్తుంది. పబ్లిక్ కీ, యాప్/వెబ్సైట్ సర్వర్తో షేర్ చేయబడుతుంది. సంబంధిత కీలతో, తక్షణమే రిజిస్టర్ చేసుకొని, సైన్ ఇన్ చేయవచ్చు."</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"మెరుగైన ఖాతా సెక్యూరిటీ"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"ప్రతి కీ దానిని క్రియేట్ చేసిన యాప్ లేదా వెబ్సైట్తో ప్రత్యేకంగా లింక్ చేయబడి ఉంటుంది, కాబట్టి మీరు పొరపాటున కూడా మోసపూరిత యాప్ లేదా వెబ్సైట్కు సైన్ ఇన్ చేయలేరు. అంతే కాకుండా, సర్వర్లు పబ్లిక్ కీలను మాత్రమే స్టోర్ చేయడం వల్ల, హ్యాకింగ్ చేయడం చాలా కష్టం."</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"అవాంతరాలు లేని పరివర్తన"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"మనం భవిష్యత్తులో పాస్వర్డ్ రహిత టెక్నాలజీని ఉపయోగించినా, పాస్కీలతో పాటు పాస్వర్డ్లు కూడా అందుబాటులో ఉంటాయి."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"మీ <xliff:g id="CREATETYPES">%1$s</xliff:g>ని ఎక్కడ సేవ్ చేయాలో ఎంచుకోండి"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"మీ సమాచారాన్ని సేవ్ చేయడం కోసం ఒక Password Managerను ఎంచుకొని, తర్వాతసారి వేగంగా సైన్ ఇన్ చేయండి"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం పాస్కీని క్రియేట్ చేయాలా?"</string>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index 5362d48..61144f9 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -5,10 +5,20 @@
<string name="string_cancel" msgid="6369133483981306063">"ยกเลิก"</string>
<string name="string_continue" msgid="1346732695941131882">"ต่อไป"</string>
<string name="string_more_options" msgid="7990658711962795124">"ตัวเลือกเพิ่มเติม"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"ดูข้อมูลเพิ่มเติม"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"ปลอดภัยขึ้นด้วยพาสคีย์"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"พาสคีย์ช่วยให้คุณไม่ต้องสร้างหรือจำรหัสผ่านที่ซับซ้อน"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"พาสคีย์คือกุญแจดิจิทัลที่เข้ารหัสซึ่งคุณสร้างโดยใช้ลายนิ้วมือ ใบหน้า หรือการล็อกหน้าจอ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ข้อมูลนี้จะบันทึกอยู่ในเครื่องมือจัดการรหัสผ่านเพื่อให้คุณลงชื่อเข้าใช้ในอุปกรณ์อื่นๆ ได้"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"ข้อมูลเพิ่มเติมเกี่ยวกับพาสคีย์"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"เทคโนโลยีที่ไม่ต้องใช้รหัสผ่าน"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"พาสคีย์ช่วยให้คุณลงชื่อเข้าใช้ได้โดยไม่ต้องใช้รหัสผ่าน ใช้เพียงแค่ลายนิ้วมือ, การจดจำใบหน้า, PIN หรือรูปแบบการลากเส้นในการยืนยันตัวตนและสร้างพาสคีย์"</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"วิทยาการเข้ารหัสคีย์สาธารณะ"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"พาสคีย์ใช้คู่คีย์การเข้ารหัสตามมาตรฐานของ FIDO Alliance (เช่น Google, Apple, Microsoft และอื่นๆ) และ W3C คู่คีย์สาธารณะและคีย์ส่วนตัวจะสร้างขึ้นสำหรับแอปหรือเว็บไซต์ที่ใช้งานคีย์ดังกล่าวต่างจากชื่อผู้ใช้และชุดอักขระที่ใช้เป็นรหัสผ่าน โดยระบบจะจัดเก็บคีย์ส่วนตัวไว้ในอุปกรณ์หรือเครื่องมือจัดการรหัสผ่านและใช้คีย์ดังกล่าวเพื่อยืนยันตัวตน ส่วนคีย์สาธารณะจะแชร์กับเซิร์ฟเวอร์ของแอปหรือเว็บไซต์ ลงทะเบียนและลงชื่อเข้าใช้ได้ทันทีด้วยคีย์ที่สอดคล้องกัน"</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"ความปลอดภัยของบัญชีที่เพิ่มมากขึ้น"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"คีย์ที่สร้างขึ้นแต่ละคีย์จะลิงก์กับแอปหรือเว็บไซต์ที่ใช้งานคีย์ดังกล่าวเท่านั้น ดังนั้นจึงไม่มีการลงชื่อเข้าใช้แอปเว็บไซต์ที่เป็นการฉ้อโกงโดยไม่ตั้งใจเกิดขึ้น นอกจากนี้ เซิร์ฟเวอร์จะบันทึกเฉพาะคีย์สาธารณะ จึงทำให้แฮ็กได้ยากขึ้น"</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"การเปลี่ยนผ่านอย่างราบรื่น"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"ในขณะที่เราก้าวไปสู่อนาคตที่ไม่ต้องใช้รหัสผ่านนั้น รหัสผ่านจะยังคงใช้ได้อยู่ควบคู่ไปกับการเปลี่ยนไปใช้พาสคีย์"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"เลือกว่าต้องการบันทึก<xliff:g id="CREATETYPES">%1$s</xliff:g>ไว้ที่ใด"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"เลือกเครื่องมือจัดการรหัสผ่านเพื่อบันทึกข้อมูลและลงชื่อเข้าใช้เร็วขึ้นในครั้งถัดไป"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"สร้างพาสคีย์สำหรับ <xliff:g id="APPNAME">%1$s</xliff:g> ไหม"</string>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index 633c3a0..1c78fb8 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Kanselahin"</string>
<string name="string_continue" msgid="1346732695941131882">"Magpatuloy"</string>
<string name="string_more_options" msgid="7990658711962795124">"Higit pang opsyon"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mas ligtas gamit ang mga passkey"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Gamit ang mga passkey, hindi mo na kailangang gumawa o tumanda ng mga komplikadong password"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ang mga passkey ay mga naka-encrypt na digital na susi na ginagawa mo gamit ang iyong fingerprint, mukha, o lock ng screen"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Sine-save ang mga ito sa isang password manager para makapag-sign in ka sa iba pang device"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"Piliin kung saan mo ise-save ang iyong <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Pumili ng password manger para ma-save ang iyong impormasyon at makapag-sign in nang mas mabilis sa susunod na pagkakataon"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Gumawa ng passkey para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index 3627e6c..5a3bcba 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"İptal"</string>
<string name="string_continue" msgid="1346732695941131882">"Devam"</string>
<string name="string_more_options" msgid="7990658711962795124">"Diğer seçenekler"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Şifre anahtarlarıyla daha yüksek güvenlik"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Şifre anahtarı kullandığınızda karmaşık şifreler oluşturmanız veya bunları hatırlamanız gerekmez"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Şifre anahtarları; parmak iziniz, yüzünüz veya ekran kilidinizi kullanarak oluşturduğunuz şifrelenmiş dijital anahtarlardır"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Diğer cihazlarda oturum açabilmeniz için şifre anahtarları bir şifre yöneticisine kaydedilir"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> bilgilerinizin kaydedileceği yeri seçin"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Bilgilerinizi kaydedip bir dahaki sefere daha hızlı oturum açmak için bir şifre yöneticisi seçin"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> için şifre anahtarı oluşturulsun mu?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> için şifre kaydedilsin mi?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> için oturum açma bilgileri kaydedilsin mi?"</string>
<string name="passkey" msgid="632353688396759522">"şifre anahtarı"</string>
<string name="password" msgid="6738570945182936667">"şifre"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"şifre anahtarları"</string>
+ <string name="passwords" msgid="5419394230391253816">"şifreler"</string>
<string name="sign_ins" msgid="4710739369149469208">"oturum aç"</string>
<string name="sign_in_info" msgid="2627704710674232328">"oturum açma bilgileri"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Şuraya kaydet: <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Başka bir cihazda şifre anahtarı oluşturulsun mu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Tüm oturum açma işlemlerinizde <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kullanılsın mı?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Bu şifre yöneticisi, şifrelerinizi ve şifre anahtarlarınızı saklayarak kolayca oturum açmanıza yardımcı olur"</string>
<string name="set_as_default" msgid="4415328591568654603">"Varsayılan olarak ayarla"</string>
<string name="use_once" msgid="9027366575315399714">"Bir kez kullanın"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> şifre • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> şifre anahtarı"</string>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index 49ef6c1..46e7649 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Скасувати"</string>
<string name="string_continue" msgid="1346732695941131882">"Продовжити"</string>
<string name="string_more_options" msgid="7990658711962795124">"Інші опції"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Ключі доступу покращують безпеку"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Маючи ключі доступу, не потрібно створювати чи запам’ятовувати складні паролі"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ключі доступу – це зашифровані цифрові ключі, які ви створюєте за допомогою відбитка пальця, фейс-контролю чи засобу розблокування екрана"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Вони зберігаються в менеджері паролів, тож ви можете входити на інших пристроях"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Виберіть, де зберігати <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Виберіть менеджер паролів, щоб зберігати свої дані й надалі входити в облікові записи швидше"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Створити ключ доступу для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Зберегти пароль для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Зберегти дані для входу для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"ключі доступу"</string>
+ <string name="passwords" msgid="5419394230391253816">"паролі"</string>
<string name="sign_ins" msgid="4710739369149469208">"дані для входу"</string>
<string name="sign_in_info" msgid="2627704710674232328">"дані для входу"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Зберегти <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> в"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Створити ключ доступу на іншому пристрої?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Використовувати сервіс <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> в усіх випадках входу?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Цей менеджер паролів зберігатиме ваші паролі та ключі доступу, щоб ви могли легко входити в облікові записи"</string>
<string name="set_as_default" msgid="4415328591568654603">"Вибрати за умовчанням"</string>
<string name="use_once" msgid="9027366575315399714">"Скористатися раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Кількість паролів: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Кількість ключів доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index 8ceb842..103ea38 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -5,31 +5,35 @@
<string name="string_cancel" msgid="6369133483981306063">"منسوخ کریں"</string>
<string name="string_continue" msgid="1346732695941131882">"جاری رکھیں"</string>
<string name="string_more_options" msgid="7990658711962795124">"مزید اختیارات"</string>
+ <string name="string_learn_more" msgid="4541600451688392447">"مزید جانیں"</string>
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"پاس کیز کے ساتھ زیادہ محفوظ"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"پاس کیز کے ساتھ آپ کو پیچیدہ پاس ورڈز تخلیق کرنے یا انہیں یاد رکھنے کی ضرورت نہیں ہے"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"پاس کیز مرموز کردہ ڈیجیٹل کلیدیں ہیں جنہیں آپ اپنا فنگر پرنٹ، چہرہ یا اسکرین لاک استعمال کرتے ہوئے تخلیق کرتے ہیں"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ان کو پاس ورڈ مینیجر میں محفوظ کیا جاتا ہے تاکہ آپ دوسرے آلات پر سائن ان کر سکیں"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
- <skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
- <skip />
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"پاس کیز کے بارے میں مزید"</string>
+ <string name="passwordless_technology_title" msgid="2497513482056606668">"بغیر پاس ورڈ والی ٹیکنالوجی"</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"پاس کیز کے ذریعے آپ پاس ورڈز پر اعتماد کیے بغیر سائن ان کر سکتے ہیں۔ اپنی شناخت کی توثیق کرنے اور پاس کی تخلیق کرنے کے لیے آپ کو صرف اپنے فنگر پرنٹ، چہرے کی شناخت، PIN استعمال کرنے کی ضرورت ہے یا پیٹرن سوائپ کریں۔"</string>
+ <string name="public_key_cryptography_title" msgid="6751970819265298039">"عوامی کلید کی کرپٹو گرافی"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO اتحاد (جس میں Google, Apple, Microsoft وغیرہ شامل ہیں) اور W3C معیارات کی بنیاد پر، پاس کیز کرپٹوگرافک کلیدوں کا جوڑا استعمال کرتی ہیں۔ صارف نام اور حروف کی اسٹرنگ کے برعکس جو ہم پاس ورڈز کے لیے استعمال کرتے ہیں، ایک ایپ یا ویب سائٹ کے لیے ایک نجی عوامی کلیدوں کا جوڑا تخلیق کیا جاتا ہے۔ نجی کلید آپ کے آلے یا پاس ورڈ مینیجر پر محفوظ طریقے سے اسٹور ہوتی ہے اور یہ آپ کی شناخت کی تصدیق کرتی ہے۔ عوامی کلید ایپ یا ویب سائٹ کے سرور کے ساتھ اشتراک کی جاتی ہے۔ متعلقہ کلیدوں کے ساتھ، آپ فوری طور پر رجسٹر اور سائن ان کر سکتے ہیں۔"</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"بہتر کردہ اکاؤنٹ کی سیکیورٹی"</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"ہر کلید خصوصی طور پر اس ایپ یا ویب سائٹ سے منسلک ہے جس کے لیے اسے تخلیق کیا گیا تھا، اس لیے آپ کبھی بھی غلطی سے کسی پر فریب ایپ یا ویب سائٹ میں سائن ان نہیں کر سکتے ہیں۔ اس کے علاوہ، چونکہ سرورز صرف عوامی کلید رکھتے ہیں، اس لیے ہیکنگ بہت مشکل ہے۔"</string>
+ <string name="seamless_transition_title" msgid="5335622196351371961">"آسان ٹرانزیشن"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"چونکہ ہم بغیر پاس ورڈ والے مستقبل کی طرف جا رہے ہیں اس کے باوجود پاس ورڈز پاس کیز کے ساتھ ہی دستیاب ہوں گے۔"</string>
+ <string name="choose_provider_title" msgid="8870795677024868108">"منتخب کریں کہ آپ کی <xliff:g id="CREATETYPES">%1$s</xliff:g> کو کہاں محفوظ کرنا ہے"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"اپنی معلومات کو محفوظ کرنے اور اگلی بار تیزی سے سائن ان کرنے کے لیے پاس ورڈ مینیجر منتخب کریں"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے پاس کی تخلیق کریں؟"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے پاس ورڈ کو محفوظ کریں؟"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے سائن ان کی معلومات محفوظ کریں؟"</string>
<string name="passkey" msgid="632353688396759522">"پاس کی"</string>
<string name="password" msgid="6738570945182936667">"پاس ورڈ"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"پاس کیز"</string>
+ <string name="passwords" msgid="5419394230391253816">"پاس ورڈز"</string>
<string name="sign_ins" msgid="4710739369149469208">"سائن انز"</string>
<string name="sign_in_info" msgid="2627704710674232328">"سائن ان کی معلومات"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> کو اس میں محفوظ کریں"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"کسی دوسرے آلے میں پاس کی تخلیق کریں؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"اپنے سبھی سائن انز کے لیے <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> کا استعمال کریں؟"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"آسانی سے سائن ان کرنے میں آپ کی مدد کرنے کے لیے یہ پاس ورڈ مینیجر آپ کے پاس ورڈز اور پاس کیز کو اسٹور کرے گا"</string>
<string name="set_as_default" msgid="4415328591568654603">"بطور ڈیفالٹ سیٹ کریں"</string>
<string name="use_once" msgid="9027366575315399714">"ایک بار استعمال کریں"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> پاس ورڈز • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> پاس کیز"</string>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index 9233a53..f815f67 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"Bekor qilish"</string>
<string name="string_continue" msgid="1346732695941131882">"Davom etish"</string>
<string name="string_more_options" msgid="7990658711962795124">"Boshqa parametrlar"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Kalitlar orqali qulay"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Kodlar yordami tufayli murakkab parollarni yaratish va eslab qolish shart emas"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Kodlar – bu barmoq izi, yuz yoki ekran qulfi yordamida yaratilgan shifrlangan raqamli identifikator."</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ular parollar menejerida saqlanadi va ulardan boshqa qurilmalarda hisobga kirib foydalanish mumkin"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> qayerga saqlanishini tanlang"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Maʼlumotlaringizni saqlash va keyingi safar tez kirish uchun parollar menejerini tanlang"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun kod yaratilsinmi?"</string>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index 94111a7..0fe35b1 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Huỷ"</string>
<string name="string_continue" msgid="1346732695941131882">"Tiếp tục"</string>
<string name="string_more_options" msgid="7990658711962795124">"Tuỳ chọn khác"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"An toàn hơn nhờ mã xác thực"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Mã xác thực giúp bạn tránh được việc phải tạo và ghi nhớ mật khẩu phức tạp"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Mã xác thực là các khoá kỹ thuật số được mã hoá mà bạn tạo bằng cách dùng vân tay, khuôn mặt hoặc phương thức khoá màn hình của mình"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Thông tin này được lưu vào trình quản lý mật khẩu nên bạn có thể đăng nhập trên các thiết bị khác"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Chọn vị trí lưu <xliff:g id="CREATETYPES">%1$s</xliff:g> của bạn"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Hãy chọn một trình quản lý mật khẩu để lưu thông tin của bạn và đăng nhập nhanh hơn trong lần tới"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Tạo mã xác thực cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Lưu mật khẩu cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Lưu thông tin đăng nhập cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"mã xác thực"</string>
<string name="password" msgid="6738570945182936667">"mật khẩu"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"mã xác thực"</string>
+ <string name="passwords" msgid="5419394230391253816">"mật khẩu"</string>
<string name="sign_ins" msgid="4710739369149469208">"thông tin đăng nhập"</string>
<string name="sign_in_info" msgid="2627704710674232328">"thông tin đăng nhập"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Lưu <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> vào"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Tạo mã xác thực trên thiết bị khác?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Dùng <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cho mọi thông tin đăng nhập của bạn?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Trình quản lý mật khẩu này sẽ lưu trữ mật khẩu và mã xác thực của bạn để bạn dễ dàng đăng nhập"</string>
<string name="set_as_default" msgid="4415328591568654603">"Đặt làm mặc định"</string>
<string name="use_once" msgid="9027366575315399714">"Dùng một lần"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mật khẩu • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> mã xác thực"</string>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 1fc42bd..78a3d22 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"取消"</string>
<string name="string_continue" msgid="1346732695941131882">"继续"</string>
<string name="string_more_options" msgid="7990658711962795124">"更多选项"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"通行密钥可提高安全性"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"借助通行密钥,您无需创建或记住复杂的密码"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"通行密钥是指您使用您的指纹、面孔或屏锁方式创建的加密数字钥匙"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"系统会将通行密钥保存到密码管理工具中,以便您在其他设备上登录"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"选择保存<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"请选择一款密码管理工具来保存您的信息,以便下次更快地登录"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要为“<xliff:g id="APPNAME">%1$s</xliff:g>”创建通行密钥吗?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"要保存“<xliff:g id="APPNAME">%1$s</xliff:g>”的密码吗?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"要保存“<xliff:g id="APPNAME">%1$s</xliff:g>”的登录信息吗?"</string>
<string name="passkey" msgid="632353688396759522">"通行密钥"</string>
<string name="password" msgid="6738570945182936667">"密码"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"通行密钥"</string>
+ <string name="passwords" msgid="5419394230391253816">"密码"</string>
<string name="sign_ins" msgid="4710739369149469208">"登录"</string>
<string name="sign_in_info" msgid="2627704710674232328">"登录信息"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"将<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>保存到"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"在其他设备上创建通行密钥?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"将“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”用于您的所有登录信息?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"此密码管理工具将会存储您的密码和通行密钥,以帮助您轻松登录"</string>
<string name="set_as_default" msgid="4415328591568654603">"设为默认项"</string>
<string name="use_once" msgid="9027366575315399714">"使用一次"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 个密码 • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 个通行密钥"</string>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index 276b936..54fe97c 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -5,25 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"取消"</string>
<string name="string_continue" msgid="1346732695941131882">"繼續"</string>
<string name="string_more_options" msgid="7990658711962795124">"更多選項"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"使用密鑰確保帳戶安全"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"有了密鑰,您便無需建立或記住複雜的密碼"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"密鑰是您使用指紋、面孔或螢幕鎖定時建立的加密數碼鑰匙"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"密鑰已儲存至密碼管理工具,方便您在其他裝置上登入"</string>
- <string name="choose_provider_title" msgid="8870795677024868108">"選擇要將<xliff:g id="CREATETYPES">%1$s</xliff:g>存在哪裡"</string>
- <string name="choose_provider_body" msgid="4967074531845147434">"選取密碼管理工具並儲存資訊,下次就能更快登入"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"選擇儲存<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"選取密碼管理工具即可儲存自己的資料,縮短下次登入的時間"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要為「<xliff:g id="APPNAME">%1$s</xliff:g>」建立密鑰嗎?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的密碼嗎?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的登入資料嗎?"</string>
<string name="passkey" msgid="632353688396759522">"密鑰"</string>
<string name="password" msgid="6738570945182936667">"密碼"</string>
- <string name="passkeys" msgid="5733880786866559847">"密碼金鑰"</string>
+ <string name="passkeys" msgid="5733880786866559847">"密鑰"</string>
<string name="passwords" msgid="5419394230391253816">"密碼"</string>
<string name="sign_ins" msgid="4710739369149469208">"登入資料"</string>
<string name="sign_in_info" msgid="2627704710674232328">"登入資料"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"將<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>儲存至"</string>
- <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"要在其他裝置上建立密碼金鑰嗎?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"要在其他裝置上建立密鑰嗎?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"要將「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」用於所有的登入資料嗎?"</string>
- <string name="use_provider_for_all_description" msgid="8466427781848268490">"這個密碼管理工具會儲存密碼和密碼金鑰,協助你輕鬆登入"</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"此密碼管理工具將儲存您的密碼和密鑰,協助您輕鬆登入"</string>
<string name="set_as_default" msgid="4415328591568654603">"設定為預設"</string>
<string name="use_once" msgid="9027366575315399714">"單次使用"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼 • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 個密鑰"</string>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index 910756e..0be95d2 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -5,10 +5,30 @@
<string name="string_cancel" msgid="6369133483981306063">"取消"</string>
<string name="string_continue" msgid="1346732695941131882">"繼續"</string>
<string name="string_more_options" msgid="7990658711962795124">"更多選項"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"使用密碼金鑰確保帳戶安全"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"有了密碼金鑰,就不必建立或記住複雜的密碼"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"密碼金鑰是你利用指紋、臉孔或螢幕鎖定功能建立的加密數位金鑰"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"密碼金鑰會儲存到密碼管理工具,方便你在其他裝置上登入"</string>
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
+ <skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
<string name="choose_provider_title" msgid="8870795677024868108">"選擇要將<xliff:g id="CREATETYPES">%1$s</xliff:g>存在哪裡"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"選取密碼管理工具並儲存資訊,下次就能更快登入"</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要為「<xliff:g id="APPNAME">%1$s</xliff:g>」建立密碼金鑰嗎?"</string>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index ab56435..f281c0d 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -5,31 +5,45 @@
<string name="string_cancel" msgid="6369133483981306063">"Khansela"</string>
<string name="string_continue" msgid="1346732695941131882">"Qhubeka"</string>
<string name="string_more_options" msgid="7990658711962795124">"Okunye okungakukhethwa kukho"</string>
+ <!-- no translation found for string_learn_more (4541600451688392447) -->
+ <skip />
<string name="passkey_creation_intro_title" msgid="4251037543787718844">"Iphephe ngokhiye bokudlula"</string>
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Ngokhiye wokudlula, awudingi ukusungula noma ukukhumbula amaphasiwedi ayinkimbinkimbi"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Okhiye bokungena bangokhiye bedijithali ababethelwe obasungula usebenzisa isigxivizo somunwe sakho, ubuso, noma ukukhiya isikrini"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Okhiye bokudlula balondolozwa kusiphathi sephasiwedi, ukuze ukwazi ukungena ngemvume kwamanye amadivayisi"</string>
- <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <!-- no translation found for more_about_passkeys_title (7797903098728837795) -->
<skip />
- <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <!-- no translation found for passwordless_technology_title (2497513482056606668) -->
<skip />
+ <!-- no translation found for passwordless_technology_detail (6853928846532955882) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_title (6751970819265298039) -->
+ <skip />
+ <!-- no translation found for public_key_cryptography_detail (6937631710280562213) -->
+ <skip />
+ <!-- no translation found for improved_account_security_title (1069841917893513424) -->
+ <skip />
+ <!-- no translation found for improved_account_security_detail (9123750251551844860) -->
+ <skip />
+ <!-- no translation found for seamless_transition_title (5335622196351371961) -->
+ <skip />
+ <!-- no translation found for seamless_transition_detail (4475509237171739843) -->
+ <skip />
+ <string name="choose_provider_title" msgid="8870795677024868108">"Khetha lapho ongagcina khona i-<xliff:g id="CREATETYPES">%1$s</xliff:g> yakho"</string>
+ <string name="choose_provider_body" msgid="4967074531845147434">"Khetha isiphathi sephasiwedi ukuze ulondoloze ulwazi lwakho futhi ungene ngemvume ngokushesha ngesikhathi esizayo."</string>
<string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Sungula ukhiye wokudlula we-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Londolozela amaphasiwedi ye-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Londoloza ulwazi lokungena lwe-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="passkey" msgid="632353688396759522">"ukhiye wokudlula"</string>
<string name="password" msgid="6738570945182936667">"iphasiwedi"</string>
- <!-- no translation found for passkeys (5733880786866559847) -->
- <skip />
- <!-- no translation found for passwords (5419394230391253816) -->
- <skip />
+ <string name="passkeys" msgid="5733880786866559847">"okhiye bokudlula"</string>
+ <string name="passwords" msgid="5419394230391253816">"amaphasiwedi"</string>
<string name="sign_ins" msgid="4710739369149469208">"ukungena ngemvume"</string>
<string name="sign_in_info" msgid="2627704710674232328">"ulwazi lokungena ngemvume"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Londoloza i-<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ku-"</string>
- <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
- <skip />
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Sungula ukhiye wokudlula kwenye idivayisi?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Sebenzisa i-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kukho konke ukungena kwakho ngemvume?"</string>
- <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Lesi siphathi sephasiwedi sizogcina amaphasiwedi akho nezikhiye zokungena ukuze zikusize ungene ngemvume kalula."</string>
<string name="set_as_default" msgid="4415328591568654603">"Setha njengokuzenzakalelayo"</string>
<string name="use_once" msgid="9027366575315399714">"Sebenzisa kanye"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Amaphasiwedi angu-<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • okhiye bokudlula abangu-<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 0620f9a..df85745 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -17,6 +17,7 @@
package com.android.credentialmanager
import android.content.Intent
+import android.credentials.ui.RequestInfo
import android.os.Bundle
import android.provider.Settings
import android.util.Log
@@ -26,89 +27,83 @@
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewmodel.compose.viewModel
-import com.android.credentialmanager.common.DialogType
-import com.android.credentialmanager.common.DialogResult
+import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
-import com.android.credentialmanager.common.ResultState
import com.android.credentialmanager.createflow.CreateCredentialScreen
import com.android.credentialmanager.createflow.CreateCredentialViewModel
import com.android.credentialmanager.getflow.GetCredentialScreen
import com.android.credentialmanager.getflow.GetCredentialViewModel
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
-import kotlinx.coroutines.launch
@ExperimentalMaterialApi
class CredentialSelectorActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val credManRepo = CredentialManagerRepo(this, intent)
- UserConfigRepo.setup(this)
- val requestInfo = credManRepo.requestInfo
- setContent {
- CredentialSelectorTheme {
- CredentialManagerBottomSheet(DialogType.toDialogType(requestInfo.type), credManRepo)
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val credManRepo = CredentialManagerRepo(this, intent)
+ UserConfigRepo.setup(this)
+ val requestInfo = credManRepo.requestInfo
+ setContent {
+ CredentialSelectorTheme {
+ CredentialManagerBottomSheet(requestInfo.type, credManRepo)
+ }
+ }
}
- }
- @ExperimentalMaterialApi
- @Composable
- fun CredentialManagerBottomSheet(dialogType: DialogType, credManRepo: CredentialManagerRepo) {
- val providerActivityResult = remember { mutableStateOf<ProviderActivityResult?>(null) }
- val launcher = rememberLauncherForActivityResult(
- ActivityResultContracts.StartIntentSenderForResult()
- ) {
- providerActivityResult.value = ProviderActivityResult(it.resultCode, it.data)
+ @ExperimentalMaterialApi
+ @Composable
+ fun CredentialManagerBottomSheet(requestType: String, credManRepo: CredentialManagerRepo) {
+ val providerActivityResult = remember { mutableStateOf<ProviderActivityResult?>(null) }
+ val launcher = rememberLauncherForActivityResult(
+ ActivityResultContracts.StartIntentSenderForResult()
+ ) {
+ providerActivityResult.value = ProviderActivityResult(it.resultCode, it.data)
+ }
+ when (requestType) {
+ RequestInfo.TYPE_CREATE -> {
+ val viewModel: CreateCredentialViewModel = viewModel {
+ CreateCredentialViewModel(credManRepo)
+ }
+ LaunchedEffect(viewModel.uiState.dialogState) {
+ handleDialogState(viewModel.uiState.dialogState)
+ }
+ providerActivityResult.value?.let {
+ viewModel.onProviderActivityResult(it)
+ providerActivityResult.value = null
+ }
+ CreateCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
+ }
+ RequestInfo.TYPE_GET -> {
+ val viewModel: GetCredentialViewModel = viewModel {
+ GetCredentialViewModel(credManRepo)
+ }
+ LaunchedEffect(viewModel.uiState.dialogState) {
+ handleDialogState(viewModel.uiState.dialogState)
+ }
+ providerActivityResult.value?.let {
+ viewModel.onProviderActivityResult(it)
+ providerActivityResult.value = null
+ }
+ GetCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
+ }
+ else -> {
+ Log.w("AccountSelector", "Unknown type, not rendering any UI")
+ this.finish()
+ }
+ }
}
- when (dialogType) {
- DialogType.CREATE_PASSKEY -> {
- val viewModel: CreateCredentialViewModel = viewModel{
- CreateCredentialViewModel(credManRepo)
- }
- lifecycleScope.launch {
- viewModel.observeDialogResult().collect{ dialogResult ->
- onCancel(dialogResult)
- }
- }
- providerActivityResult.value?.let {
- viewModel.onProviderActivityResult(it)
- providerActivityResult.value = null
- }
- CreateCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
- }
- DialogType.GET_CREDENTIALS -> {
- val viewModel: GetCredentialViewModel = viewModel{
- GetCredentialViewModel(credManRepo)
- }
- lifecycleScope.launch {
- viewModel.observeDialogResult().collect{ dialogResult ->
- onCancel(dialogResult)
- }
- }
- providerActivityResult.value?.let {
- viewModel.onProviderActivityResult(it)
- providerActivityResult.value = null
- }
- GetCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
- }
- else -> {
- Log.w("AccountSelector", "Unknown type, not rendering any UI")
- this.finish()
- }
- }
- }
- private fun onCancel(dialogResut: DialogResult) {
- if (dialogResut.resultState == ResultState
- .COMPLETE || dialogResut.resultState == ResultState.NORMAL_CANCELED) {
- this@CredentialSelectorActivity.finish()
- } else if (dialogResut.resultState == ResultState.LAUNCH_SETTING_CANCELED) {
- this@CredentialSelectorActivity.startActivity(Intent(Settings.ACTION_SYNC_SETTINGS))
- this@CredentialSelectorActivity.finish()
+ private fun handleDialogState(dialogState: DialogState) {
+ if (dialogState == DialogState.COMPLETE) {
+ Log.i("AccountSelector", "Received signal to finish the activity.")
+ this@CredentialSelectorActivity.finish()
+ } else if (dialogState == DialogState.CANCELED_FOR_SETTINGS) {
+ Log.i("AccountSelector", "Received signal to finish the activity and launch settings.")
+ this@CredentialSelectorActivity.startActivity(Intent(Settings.ACTION_SYNC_SETTINGS))
+ this@CredentialSelectorActivity.finish()
+ }
}
- }
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
index 743f49b..6d07df7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
@@ -16,6 +16,12 @@
package com.android.credentialmanager.common
+enum class DialogState {
+ ACTIVE,
+ COMPLETE,
+ CANCELED_FOR_SETTINGS,
+}
+
enum class ResultState {
COMPLETE,
NORMAL_CANCELED,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
index b5e9fd00..f40dc7e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
@@ -19,16 +19,15 @@
import android.credentials.ui.RequestInfo
enum class DialogType {
- CREATE_PASSKEY,
+ CREATE_CREDENTIAL,
GET_CREDENTIALS,
- CREATE_PASSWORD,
UNKNOWN;
companion object {
fun toDialogType(value: String): DialogType {
return when (value) {
RequestInfo.TYPE_GET -> GET_CREDENTIALS
- RequestInfo.TYPE_CREATE -> CREATE_PASSKEY
+ RequestInfo.TYPE_CREATE -> CREATE_CREDENTIAL
else -> UNKNOWN
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ProviderActivityState.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ProviderActivityState.kt
new file mode 100644
index 0000000..b47d0e5
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ProviderActivityState.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common
+
+enum class ProviderActivityState {
+ /** No provider activity is active nor is any ready for launch, */
+ NOT_APPLICABLE,
+ /** Ready to launch the provider activity. */
+ READY_TO_LAUNCH,
+ /** The provider activity is launched and we are waiting for its result. We should hide our UI
+ * content when this happens. */
+ PENDING,
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 1e1c833..5e432b9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -37,6 +37,7 @@
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.R
+import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
import com.android.credentialmanager.common.material.ModalBottomSheetValue
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
@@ -66,63 +67,83 @@
sheetState = state,
sheetContent = {
val uiState = viewModel.uiState
- if (!uiState.hidden) {
- when (uiState.currentScreenState) {
- CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
- onConfirm = viewModel::onConfirmIntro,
- onLearnMore = viewModel::onLearnMore,
- )
- CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- enabledProviderList = uiState.enabledProviders,
- disabledProviderList = uiState.disabledProviders,
- sortedCreateOptionsPairs = uiState.sortedCreateOptionsPairs,
- onOptionSelected = viewModel::onEntrySelectedFromFirstUseScreen,
- onDisabledProvidersSelected = viewModel::onDisabledProvidersSelected,
- onMoreOptionsSelected = viewModel::onMoreOptionsSelectedOnProviderSelection,
- )
- CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- enabledProviderList = uiState.enabledProviders,
- providerInfo = uiState.activeEntry?.activeProvider!!,
- createOptionInfo = uiState.activeEntry.activeEntryInfo as CreateOptionInfo,
- onOptionSelected = viewModel::onEntrySelected,
- onConfirm = viewModel::onConfirmEntrySelected,
- onMoreOptionsSelected = viewModel::onMoreOptionsSelectedOnCreationSelection,
- )
- CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- enabledProviderList = uiState.enabledProviders,
- disabledProviderList = uiState.disabledProviders,
- sortedCreateOptionsPairs = uiState.sortedCreateOptionsPairs,
- hasDefaultProvider = uiState.hasDefaultProvider,
- isFromProviderSelection = uiState.isFromProviderSelection!!,
- onBackProviderSelectionButtonSelected =
- viewModel::onBackProviderSelectionButtonSelected,
- onBackCreationSelectionButtonSelected =
- viewModel::onBackCreationSelectionButtonSelected,
- onOptionSelected = viewModel::onEntrySelectedFromMoreOptionScreen,
- onDisabledProvidersSelected = viewModel::onDisabledProvidersSelected,
- onRemoteEntrySelected = viewModel::onEntrySelected,
- )
- CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
- providerInfo = uiState.activeEntry?.activeProvider!!,
- onChangeDefaultSelected = viewModel::onChangeDefaultSelected,
- onUseOnceSelected = viewModel::onUseOnceSelected,
- )
- CreateScreenState.EXTERNAL_ONLY_SELECTION -> ExternalOnlySelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- activeRemoteEntry = uiState.activeEntry?.activeEntryInfo!!,
- onOptionSelected = viewModel::onEntrySelected,
- onConfirm = viewModel::onConfirmEntrySelected,
- )
- CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO -> MoreAboutPasskeysIntroCard(
- onBackPasskeyIntroButtonSelected =
- viewModel::onBackPasskeyIntroButtonSelected,
- )
+ // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
+ // background color even when the content should be hidden while waiting for
+ // results from the provider app.
+ when (uiState.providerActivityState) {
+ ProviderActivityState.NOT_APPLICABLE -> {
+ when (uiState.currentScreenState) {
+ CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
+ onConfirm = viewModel::onConfirmIntro,
+ onLearnMore = viewModel::onLearnMore,
+ )
+ CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ enabledProviderList = uiState.enabledProviders,
+ disabledProviderList = uiState.disabledProviders,
+ sortedCreateOptionsPairs = uiState.sortedCreateOptionsPairs,
+ onOptionSelected = viewModel::onEntrySelectedFromFirstUseScreen,
+ onDisabledProvidersSelected =
+ viewModel::onDisabledProvidersSelected,
+ onMoreOptionsSelected =
+ viewModel::onMoreOptionsSelectedOnProviderSelection,
+ )
+ CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ enabledProviderList = uiState.enabledProviders,
+ providerInfo = uiState.activeEntry?.activeProvider!!,
+ createOptionInfo =
+ uiState.activeEntry.activeEntryInfo as CreateOptionInfo,
+ onOptionSelected = viewModel::onEntrySelected,
+ onConfirm = viewModel::onConfirmEntrySelected,
+ onMoreOptionsSelected =
+ viewModel::onMoreOptionsSelectedOnCreationSelection,
+ )
+ CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ enabledProviderList = uiState.enabledProviders,
+ disabledProviderList = uiState.disabledProviders,
+ sortedCreateOptionsPairs = uiState.sortedCreateOptionsPairs,
+ hasDefaultProvider = uiState.hasDefaultProvider,
+ isFromProviderSelection = uiState.isFromProviderSelection!!,
+ onBackProviderSelectionButtonSelected =
+ viewModel::onBackProviderSelectionButtonSelected,
+ onBackCreationSelectionButtonSelected =
+ viewModel::onBackCreationSelectionButtonSelected,
+ onOptionSelected =
+ viewModel::onEntrySelectedFromMoreOptionScreen,
+ onDisabledProvidersSelected =
+ viewModel::onDisabledProvidersSelected,
+ onRemoteEntrySelected = viewModel::onEntrySelected,
+ )
+ CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
+ providerInfo = uiState.activeEntry?.activeProvider!!,
+ onChangeDefaultSelected = viewModel::onChangeDefaultSelected,
+ onUseOnceSelected = viewModel::onUseOnceSelected,
+ )
+ CreateScreenState.EXTERNAL_ONLY_SELECTION -> ExternalOnlySelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ activeRemoteEntry = uiState.activeEntry?.activeEntryInfo!!,
+ onOptionSelected = viewModel::onEntrySelected,
+ onConfirm = viewModel::onConfirmEntrySelected,
+ )
+ CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO ->
+ MoreAboutPasskeysIntroCard(
+ onBackPasskeyIntroButtonSelected =
+ viewModel::onBackPasskeyIntroButtonSelected,
+ )
+ }
}
- } else if (uiState.selectedEntry != null && !uiState.providerActivityPending) {
- viewModel.launchProviderUi(providerActivityLauncher)
+ ProviderActivityState.READY_TO_LAUNCH -> {
+ // Launch only once per providerActivityState change so that the provider
+ // UI will not be accidentally launched twice.
+ LaunchedEffect(uiState.providerActivityState) {
+ viewModel.launchProviderUi(providerActivityLauncher)
+ }
+ }
+ ProviderActivityState.PENDING -> {
+ // Hide our content when the provider activity is active.
+ }
}
},
scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
@@ -986,7 +1007,9 @@
)
// TODO: Update the subtitle once design is confirmed
TextSecondary(
- text = disabledProviders.joinToString(separator = " • ") { it.displayName },
+ text = disabledProviders.joinToString(separator = " • ") {
+ it.displayName
+ },
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
index a9b1d332..d3cf241 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
@@ -28,240 +28,231 @@
import com.android.credentialmanager.CreateFlowUtils
import com.android.credentialmanager.CredentialManagerRepo
import com.android.credentialmanager.UserConfigRepo
-import com.android.credentialmanager.common.DialogResult
+import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
-import com.android.credentialmanager.common.ResultState
-import kotlinx.coroutines.channels.BufferOverflow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
+import com.android.credentialmanager.common.ProviderActivityState
data class CreateCredentialUiState(
- val enabledProviders: List<EnabledProviderInfo>,
- val disabledProviders: List<DisabledProviderInfo>? = null,
- val currentScreenState: CreateScreenState,
- val requestDisplayInfo: RequestDisplayInfo,
- val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- // Should not change with the real time update of default provider, only determine whether we're
- // showing provider selection page at the beginning
- val hasDefaultProvider: Boolean,
- val activeEntry: ActiveEntry? = null,
- val selectedEntry: EntryInfo? = null,
- val hidden: Boolean = false,
- val providerActivityPending: Boolean = false,
- val isFromProviderSelection: Boolean? = null,
+ val enabledProviders: List<EnabledProviderInfo>,
+ val disabledProviders: List<DisabledProviderInfo>? = null,
+ val currentScreenState: CreateScreenState,
+ val requestDisplayInfo: RequestDisplayInfo,
+ val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
+ // Should not change with the real time update of default provider, only determine whether
+ // we're showing provider selection page at the beginning
+ val hasDefaultProvider: Boolean,
+ val activeEntry: ActiveEntry? = null,
+ val selectedEntry: EntryInfo? = null,
+ val providerActivityState: ProviderActivityState =
+ ProviderActivityState.NOT_APPLICABLE,
+ val isFromProviderSelection: Boolean? = null,
+ val dialogState: DialogState = DialogState.ACTIVE,
)
class CreateCredentialViewModel(
- private val credManRepo: CredentialManagerRepo,
- userConfigRepo: UserConfigRepo = UserConfigRepo.getInstance(),
+ private val credManRepo: CredentialManagerRepo,
+ userConfigRepo: UserConfigRepo = UserConfigRepo.getInstance(),
) : ViewModel() {
- var providerEnableListUiState = credManRepo.getCreateProviderEnableListInitialUiState()
+ val providerEnableListUiState = credManRepo.getCreateProviderEnableListInitialUiState()
- var providerDisableListUiState = credManRepo.getCreateProviderDisableListInitialUiState()
+ val providerDisableListUiState = credManRepo.getCreateProviderDisableListInitialUiState()
- var requestDisplayInfoUiState = credManRepo.getCreateRequestDisplayInfoInitialUiState()
+ val requestDisplayInfoUiState = credManRepo.getCreateRequestDisplayInfoInitialUiState()
- var defaultProviderId = userConfigRepo.getDefaultProviderId()
+ val defaultProviderId = userConfigRepo.getDefaultProviderId()
- var isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
+ val isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
- var uiState by mutableStateOf(
- CreateFlowUtils.toCreateCredentialUiState(
- providerEnableListUiState,
- providerDisableListUiState,
- defaultProviderId,
- requestDisplayInfoUiState,
- false,
- isPasskeyFirstUse))
- private set
+ var uiState by mutableStateOf(
+ CreateFlowUtils.toCreateCredentialUiState(
+ providerEnableListUiState,
+ providerDisableListUiState,
+ defaultProviderId,
+ requestDisplayInfoUiState,
+ false,
+ isPasskeyFirstUse))
+ private set
- val dialogResult: MutableSharedFlow<DialogResult> =
- MutableSharedFlow(replay = 0, extraBufferCapacity = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST)
-
- fun observeDialogResult(): SharedFlow<DialogResult> {
- return dialogResult
- }
-
- fun onConfirmIntro() {
- uiState = CreateFlowUtils.toCreateCredentialUiState(
- providerEnableListUiState, providerDisableListUiState, defaultProviderId,
- requestDisplayInfoUiState, true, isPasskeyFirstUse)
- UserConfigRepo.getInstance().setIsPasskeyFirstUse(false)
- }
-
- fun getProviderInfoByName(providerId: String): EnabledProviderInfo {
- return uiState.enabledProviders.single {
- it.id == providerId
+ fun onConfirmIntro() {
+ uiState = CreateFlowUtils.toCreateCredentialUiState(
+ providerEnableListUiState, providerDisableListUiState, defaultProviderId,
+ requestDisplayInfoUiState, true, isPasskeyFirstUse)
+ UserConfigRepo.getInstance().setIsPasskeyFirstUse(false)
}
- }
- fun onMoreOptionsSelectedOnProviderSelection() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = true
- )
- }
+ fun getProviderInfoByName(providerId: String): EnabledProviderInfo {
+ return uiState.enabledProviders.single {
+ it.id == providerId
+ }
+ }
- fun onMoreOptionsSelectedOnCreationSelection() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = false
- )
- }
+ fun onMoreOptionsSelectedOnProviderSelection() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
+ isFromProviderSelection = true
+ )
+ }
- fun onBackProviderSelectionButtonSelected() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.PROVIDER_SELECTION,
- )
- }
+ fun onMoreOptionsSelectedOnCreationSelection() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
+ isFromProviderSelection = false
+ )
+ }
- fun onBackCreationSelectionButtonSelected() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- )
- }
+ fun onBackProviderSelectionButtonSelected() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.PROVIDER_SELECTION,
+ )
+ }
- fun onBackPasskeyIntroButtonSelected() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.PASSKEY_INTRO,
- )
- }
+ fun onBackCreationSelectionButtonSelected() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
+ )
+ }
- fun onEntrySelectedFromMoreOptionScreen(activeEntry: ActiveEntry) {
- uiState = uiState.copy(
- currentScreenState = if (
- activeEntry.activeProvider.id == UserConfigRepo.getInstance().getDefaultProviderId()
- ) CreateScreenState.CREATION_OPTION_SELECTION else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
- activeEntry = activeEntry
- )
- }
+ fun onBackPasskeyIntroButtonSelected() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.PASSKEY_INTRO,
+ )
+ }
- fun onEntrySelectedFromFirstUseScreen(activeEntry: ActiveEntry) {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- activeEntry = activeEntry
- )
- val providerId = uiState.activeEntry?.activeProvider?.id
- onDefaultChanged(providerId)
- }
+ fun onEntrySelectedFromMoreOptionScreen(activeEntry: ActiveEntry) {
+ uiState = uiState.copy(
+ currentScreenState =
+ if (activeEntry.activeProvider.id ==
+ UserConfigRepo.getInstance().getDefaultProviderId())
+ CreateScreenState.CREATION_OPTION_SELECTION
+ else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
+ activeEntry = activeEntry
+ )
+ }
- fun onDisabledProvidersSelected() {
- credManRepo.onSettingLaunchCancel()
- dialogResult.tryEmit(DialogResult(ResultState.LAUNCH_SETTING_CANCELED))
- }
+ fun onEntrySelectedFromFirstUseScreen(activeEntry: ActiveEntry) {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
+ activeEntry = activeEntry
+ )
+ val providerId = uiState.activeEntry?.activeProvider?.id
+ onDefaultChanged(providerId)
+ }
- fun onCancel() {
- credManRepo.onUserCancel()
- dialogResult.tryEmit(DialogResult(ResultState.NORMAL_CANCELED))
- }
+ fun onDisabledProvidersSelected() {
+ credManRepo.onSettingLaunchCancel()
+ uiState = uiState.copy(dialogState = DialogState.CANCELED_FOR_SETTINGS)
+ }
- fun onLearnMore() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO,
- )
- }
+ fun onCancel() {
+ credManRepo.onUserCancel()
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
- fun onChangeDefaultSelected() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- )
- val providerId = uiState.activeEntry?.activeProvider?.id
- onDefaultChanged(providerId)
- }
+ fun onLearnMore() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO,
+ )
+ }
- fun onUseOnceSelected() {
- uiState = uiState.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- )
- }
+ fun onChangeDefaultSelected() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
+ )
+ val providerId = uiState.activeEntry?.activeProvider?.id
+ onDefaultChanged(providerId)
+ }
- fun onDefaultChanged(providerId: String?) {
- if (providerId != null) {
- Log.d(
- "Account Selector", "Default provider changed to: " +
+ fun onUseOnceSelected() {
+ uiState = uiState.copy(
+ currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
+ )
+ }
+
+ fun onDefaultChanged(providerId: String?) {
+ if (providerId != null) {
+ Log.d(
+ "Account Selector", "Default provider changed to: " +
" {provider=$providerId")
- UserConfigRepo.getInstance().setDefaultProvider(providerId)
- } else {
- Log.w("Account Selector", "Null provider is being changed")
+ UserConfigRepo.getInstance().setDefaultProvider(providerId)
+ } else {
+ Log.w("Account Selector", "Null provider is being changed")
+ }
}
- }
- fun onEntrySelected(selectedEntry: EntryInfo) {
- val providerId = selectedEntry.providerId
- val entryKey = selectedEntry.entryKey
- val entrySubkey = selectedEntry.entrySubkey
- Log.d(
- "Account Selector", "Option selected for entry: " +
- " {provider=$providerId, key=$entryKey, subkey=$entrySubkey")
- if (selectedEntry.pendingIntent != null) {
- uiState = uiState.copy(
- selectedEntry = selectedEntry,
- hidden = true,
- )
- } else {
- credManRepo.onOptionSelected(
- providerId,
- entryKey,
- entrySubkey
- )
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
+ fun onEntrySelected(selectedEntry: EntryInfo) {
+ val providerId = selectedEntry.providerId
+ val entryKey = selectedEntry.entryKey
+ val entrySubkey = selectedEntry.entrySubkey
+ Log.d(
+ "Account Selector", "Option selected for entry: " +
+ " {provider=$providerId, key=$entryKey, subkey=$entrySubkey")
+ if (selectedEntry.pendingIntent != null) {
+ uiState = uiState.copy(
+ selectedEntry = selectedEntry,
+ providerActivityState = ProviderActivityState.READY_TO_LAUNCH,
+ )
+ } else {
+ credManRepo.onOptionSelected(
+ providerId,
+ entryKey,
+ entrySubkey
+ )
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
- }
- fun launchProviderUi(
- launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
- ) {
- val entry = uiState.selectedEntry
- if (entry != null && entry.pendingIntent != null) {
- uiState = uiState.copy(
- providerActivityPending = true,
- )
- val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
- .setFillInIntent(entry.fillInIntent).build()
- launcher.launch(intentSenderRequest)
- } else {
- Log.w("Account Selector", "No provider UI to launch")
+ fun launchProviderUi(
+ launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+ ) {
+ val entry = uiState.selectedEntry
+ if (entry != null && entry.pendingIntent != null) {
+ uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
+ val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+ .setFillInIntent(entry.fillInIntent).build()
+ launcher.launch(intentSenderRequest)
+ } else {
+ Log.w("Account Selector", "No provider UI to launch")
+ }
}
- }
- fun onConfirmEntrySelected() {
- val selectedEntry = uiState.activeEntry?.activeEntryInfo
- if (selectedEntry != null) {
- onEntrySelected(selectedEntry)
- } else {
- Log.w("Account Selector",
- "Illegal state: confirm is pressed but activeEntry isn't set.")
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
+ fun onConfirmEntrySelected() {
+ val selectedEntry = uiState.activeEntry?.activeEntryInfo
+ if (selectedEntry != null) {
+ onEntrySelected(selectedEntry)
+ } else {
+ Log.w("Account Selector",
+ "Illegal state: confirm is pressed but activeEntry isn't set.")
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
- }
- fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
- val entry = uiState.selectedEntry
- val resultCode = providerActivityResult.resultCode
- val resultData = providerActivityResult.data
- if (resultCode == Activity.RESULT_CANCELED) {
- // Re-display the CredMan UI if the user canceled from the provider UI.
- uiState = uiState.copy(
- selectedEntry = null,
- hidden = false,
- providerActivityPending = false,
- )
- } else {
- if (entry != null) {
- val providerId = entry.providerId
- Log.d("Account Selector", "Got provider activity result: {provider=" +
- "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
- "resultCode=$resultCode, resultData=$resultData}"
- )
- credManRepo.onOptionSelected(
- providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
- )
- } else {
- Log.w("Account Selector",
- "Illegal state: received a provider result but found no matching entry.")
- }
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
+ fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
+ val entry = uiState.selectedEntry
+ val resultCode = providerActivityResult.resultCode
+ val resultData = providerActivityResult.data
+ if (resultCode == Activity.RESULT_CANCELED) {
+ // Re-display the CredMan UI if the user canceled from the provider UI.
+ Log.d("Account Selector", "The provider activity was cancelled," +
+ " re-displaying our UI.")
+ uiState = uiState.copy(
+ selectedEntry = null,
+ providerActivityState = ProviderActivityState.NOT_APPLICABLE,
+ )
+ } else {
+ if (entry != null) {
+ val providerId = entry.providerId
+ Log.d("Account Selector", "Got provider activity result: {provider=" +
+ "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
+ "resultCode=$resultCode, resultData=$resultData}"
+ )
+ credManRepo.onOptionSelected(
+ providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
+ )
+ } else {
+ Log.w("Account Selector",
+ "Illegal state: received a provider result but found no matching entry.")
+ }
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
- }
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 420b4d5..b30d1ec 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -59,6 +59,7 @@
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.R
+import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
import com.android.credentialmanager.common.material.ModalBottomSheetValue
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
@@ -90,30 +91,42 @@
modifier = Modifier.background(Color.Transparent),
sheetState = state,
sheetContent = {
- // TODO: hide UI at top level
- if (!uiState.hidden) {
- if (uiState.currentScreenState == GetScreenState.PRIMARY_SELECTION) {
- PrimarySelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- providerDisplayInfo = uiState.providerDisplayInfo,
- providerInfoList = uiState.providerInfoList,
- activeEntry = uiState.activeEntry,
- onEntrySelected = viewModel::onEntrySelected,
- onConfirm = viewModel::onConfirmEntrySelected,
- onMoreOptionSelected = viewModel::onMoreOptionSelected,
- )
- } else {
- AllSignInOptionCard(
- providerInfoList = uiState.providerInfoList,
- providerDisplayInfo = uiState.providerDisplayInfo,
- onEntrySelected = viewModel::onEntrySelected,
- onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
- onCancel = viewModel::onCancel,
- isNoAccount = uiState.isNoAccount,
- )
+ // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
+ // background color even when the content should be hidden while waiting for
+ // results from the provider app.
+ when (uiState.providerActivityState) {
+ ProviderActivityState.NOT_APPLICABLE -> {
+ if (uiState.currentScreenState == GetScreenState.PRIMARY_SELECTION) {
+ PrimarySelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ providerDisplayInfo = uiState.providerDisplayInfo,
+ providerInfoList = uiState.providerInfoList,
+ activeEntry = uiState.activeEntry,
+ onEntrySelected = viewModel::onEntrySelected,
+ onConfirm = viewModel::onConfirmEntrySelected,
+ onMoreOptionSelected = viewModel::onMoreOptionSelected,
+ )
+ } else {
+ AllSignInOptionCard(
+ providerInfoList = uiState.providerInfoList,
+ providerDisplayInfo = uiState.providerDisplayInfo,
+ onEntrySelected = viewModel::onEntrySelected,
+ onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
+ onCancel = viewModel::onCancel,
+ isNoAccount = uiState.isNoAccount,
+ )
+ }
}
- } else if (uiState.selectedEntry != null && !uiState.providerActivityPending) {
- viewModel.launchProviderUi(providerActivityLauncher)
+ ProviderActivityState.READY_TO_LAUNCH -> {
+ // Launch only once per providerActivityState change so that the provider
+ // UI will not be accidentally launched twice.
+ LaunchedEffect(uiState.providerActivityState) {
+ viewModel.launchProviderUi(providerActivityLauncher)
+ }
+ }
+ ProviderActivityState.PENDING -> {
+ // Hide our content when the provider activity is active.
+ }
}
},
scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
@@ -225,7 +238,7 @@
color = Color.Transparent
)
var totalEntriesCount = sortedUserNameToCredentialEntryList
- .flatMap{ it.sortedCredentialEntryList}.size + authenticationEntryList
+ .flatMap { it.sortedCredentialEntryList }.size + authenticationEntryList
.size + providerInfoList.flatMap { it.actionEntryList }.size
if (providerDisplayInfo.remoteEntry != null) totalEntriesCount += 1
// Row horizontalArrangement differs on only one actionButton(should place on most
@@ -528,10 +541,10 @@
credentialEntryInfo.credentialTypeDisplayName
else
credentialEntryInfo.credentialTypeDisplayName +
- stringResource(
- R.string.get_dialog_sign_in_type_username_separator
- ) +
- credentialEntryInfo.displayName
+ stringResource(
+ R.string.get_dialog_sign_in_type_username_separator
+ ) +
+ credentialEntryInfo.displayName
},
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(bottom = 16.dp, start = 5.dp)
@@ -561,7 +574,7 @@
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth().padding(horizontal = 5.dp),
- ) {
+ ) {
Column() {
// TODO: fix the text values.
TextOnSurfaceVariant(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index c72ae72..065a2de 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -26,251 +26,242 @@
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.android.credentialmanager.CredentialManagerRepo
-import com.android.credentialmanager.common.DialogResult
+import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
-import com.android.credentialmanager.common.ResultState
+import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential
import com.android.internal.util.Preconditions
-import kotlinx.coroutines.channels.BufferOverflow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
data class GetCredentialUiState(
- val providerInfoList: List<ProviderInfo>,
- val requestDisplayInfo: RequestDisplayInfo,
- val currentScreenState: GetScreenState = toGetScreenState(providerInfoList),
- val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
- val selectedEntry: EntryInfo? = null,
- val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
- val hidden: Boolean = false,
- val providerActivityPending: Boolean = false,
- val isNoAccount: Boolean = false,
+ val providerInfoList: List<ProviderInfo>,
+ val requestDisplayInfo: RequestDisplayInfo,
+ val currentScreenState: GetScreenState = toGetScreenState(providerInfoList),
+ val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
+ val selectedEntry: EntryInfo? = null,
+ val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
+ val providerActivityState: ProviderActivityState =
+ ProviderActivityState.NOT_APPLICABLE,
+ val isNoAccount: Boolean = false,
+ val dialogState: DialogState = DialogState.ACTIVE,
)
class GetCredentialViewModel(private val credManRepo: CredentialManagerRepo) : ViewModel() {
- var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
- private set
+ var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
+ private set
- val dialogResult: MutableSharedFlow<DialogResult> =
- MutableSharedFlow(replay = 0, extraBufferCapacity = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST)
-
- fun observeDialogResult(): SharedFlow<DialogResult> {
- return dialogResult
- }
-
- fun onEntrySelected(entry: EntryInfo) {
- Log.d("Account Selector", "credential selected:" +
- " {provider=${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
- if (entry.pendingIntent != null) {
- uiState = uiState.copy(
- selectedEntry = entry,
- hidden = true,
- )
- } else {
- credManRepo.onOptionSelected(entry.providerId, entry.entryKey, entry.entrySubkey)
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
+ fun onEntrySelected(entry: EntryInfo) {
+ Log.d("Account Selector", "credential selected: {provider=${entry.providerId}" +
+ ", key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
+ if (entry.pendingIntent != null) {
+ uiState = uiState.copy(
+ selectedEntry = entry,
+ providerActivityState = ProviderActivityState.READY_TO_LAUNCH,
+ )
+ } else {
+ credManRepo.onOptionSelected(entry.providerId, entry.entryKey, entry.entrySubkey)
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
- }
- fun onConfirmEntrySelected() {
- val activeEntry = uiState.activeEntry
- if (activeEntry != null) {
- onEntrySelected(activeEntry)
- } else {
- Log.w("Account Selector",
- "Illegal state: confirm is pressed but activeEntry isn't set.")
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
+ fun onConfirmEntrySelected() {
+ val activeEntry = uiState.activeEntry
+ if (activeEntry != null) {
+ onEntrySelected(activeEntry)
+ } else {
+ Log.w("Account Selector",
+ "Illegal state: confirm is pressed but activeEntry isn't set.")
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
- }
- fun launchProviderUi(
- launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
- ) {
- val entry = uiState.selectedEntry
- if (entry != null && entry.pendingIntent != null) {
- uiState = uiState.copy(
- providerActivityPending = true,
- )
- val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
- .setFillInIntent(entry.fillInIntent).build()
- launcher.launch(intentSenderRequest)
- } else {
- Log.w("Account Selector", "No provider UI to launch")
+ fun launchProviderUi(
+ launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+ ) {
+ val entry = uiState.selectedEntry
+ if (entry != null && entry.pendingIntent != null) {
+ Log.d("credentials", "Launching provider activity")
+ uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
+ val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+ .setFillInIntent(entry.fillInIntent).build()
+ launcher.launch(intentSenderRequest)
+ } else {
+ Log.w("Account Selector", "No provider UI to launch")
+ }
}
- }
- fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
- val entry = uiState.selectedEntry
- val resultCode = providerActivityResult.resultCode
- val resultData = providerActivityResult.data
- if (resultCode == Activity.RESULT_CANCELED) {
- // Re-display the CredMan UI if the user canceled from the provider UI.
- uiState = uiState.copy(
- selectedEntry = null,
- hidden = false,
- providerActivityPending = false,
- )
- } else {
- if (entry != null) {
- Log.d("Account Selector", "Got provider activity result: {provider=" +
- "${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
- "resultCode=$resultCode, resultData=$resultData}"
+ fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
+ val entry = uiState.selectedEntry
+ val resultCode = providerActivityResult.resultCode
+ val resultData = providerActivityResult.data
+ if (resultCode == Activity.RESULT_CANCELED) {
+ // Re-display the CredMan UI if the user canceled from the provider UI.
+ Log.d("Account Selector", "The provider activity was cancelled," +
+ " re-displaying our UI.")
+ uiState = uiState.copy(
+ selectedEntry = null,
+ providerActivityState = ProviderActivityState.NOT_APPLICABLE,
+ )
+ } else {
+ if (entry != null) {
+ Log.d("Account Selector", "Got provider activity result: {provider=" +
+ "${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}" +
+ ", resultCode=$resultCode, resultData=$resultData}"
+ )
+ credManRepo.onOptionSelected(
+ entry.providerId, entry.entryKey, entry.entrySubkey,
+ resultCode, resultData,
+ )
+ } else {
+ Log.w("Account Selector",
+ "Illegal state: received a provider result but found no matching entry.")
+ }
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
+ }
+
+ fun onMoreOptionSelected() {
+ Log.d("Account Selector", "More Option selected")
+ uiState = uiState.copy(
+ currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS
)
- credManRepo.onOptionSelected(
- entry.providerId, entry.entryKey, entry.entrySubkey,
- resultCode, resultData,
- )
- } else {
- Log.w("Account Selector",
- "Illegal state: received a provider result but found no matching entry.")
- }
- dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
- }
- fun onMoreOptionSelected() {
- Log.d("Account Selector", "More Option selected")
- uiState = uiState.copy(
- currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS
- )
- }
+ fun onMoreOptionOnSnackBarSelected(isNoAccount: Boolean) {
+ Log.d("Account Selector", "More Option on snackBar selected")
+ uiState = uiState.copy(
+ currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS,
+ isNoAccount = isNoAccount,
+ )
+ }
- fun onMoreOptionOnSnackBarSelected(isNoAccount: Boolean) {
- Log.d("Account Selector", "More Option on snackBar selected")
- uiState = uiState.copy(
- currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS,
- isNoAccount = isNoAccount,
- )
- }
+ fun onBackToPrimarySelectionScreen() {
+ uiState = uiState.copy(
+ currentScreenState = GetScreenState.PRIMARY_SELECTION
+ )
+ }
- fun onBackToPrimarySelectionScreen() {
- uiState = uiState.copy(
- currentScreenState = GetScreenState.PRIMARY_SELECTION
- )
- }
-
- fun onCancel() {
- credManRepo.onUserCancel()
- dialogResult.tryEmit(DialogResult(ResultState.NORMAL_CANCELED))
- }
+ fun onCancel() {
+ credManRepo.onUserCancel()
+ uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+ }
}
private fun toProviderDisplayInfo(
- providerInfoList: List<ProviderInfo>
+ providerInfoList: List<ProviderInfo>
): ProviderDisplayInfo {
- val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
- val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
- val remoteEntryList = mutableListOf<RemoteEntryInfo>()
- providerInfoList.forEach { providerInfo ->
- if (providerInfo.authenticationEntry != null) {
- authenticationEntryList.add(providerInfo.authenticationEntry)
- }
- if (providerInfo.remoteEntry != null) {
- remoteEntryList.add(providerInfo.remoteEntry)
- }
-
- providerInfo.credentialEntryList.forEach {
- userNameToCredentialEntryMap.compute(
- it.userName
- ) {
- _, v ->
- if (v == null) {
- mutableListOf(it)
- } else {
- v.add(it)
- v
+ val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
+ val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
+ val remoteEntryList = mutableListOf<RemoteEntryInfo>()
+ providerInfoList.forEach { providerInfo ->
+ if (providerInfo.authenticationEntry != null) {
+ authenticationEntryList.add(providerInfo.authenticationEntry)
}
- }
+ if (providerInfo.remoteEntry != null) {
+ remoteEntryList.add(providerInfo.remoteEntry)
+ }
+
+ providerInfo.credentialEntryList.forEach {
+ userNameToCredentialEntryMap.compute(
+ it.userName
+ ) { _, v ->
+ if (v == null) {
+ mutableListOf(it)
+ } else {
+ v.add(it)
+ v
+ }
+ }
+ }
}
- }
- // There can only be at most one remote entry
- // TODO: fail elegantly
- Preconditions.checkState(remoteEntryList.size <= 1)
+ // There can only be at most one remote entry
+ // TODO: fail elegantly
+ Preconditions.checkState(remoteEntryList.size <= 1)
- // Compose sortedUserNameToCredentialEntryList
- val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp()
- // Sort per username
- userNameToCredentialEntryMap.values.forEach {
- it.sortWith(comparator)
- }
- // Transform to list of PerUserNameCredentialEntryLists and then sort across usernames
- val sortedUserNameToCredentialEntryList = userNameToCredentialEntryMap.map {
- PerUserNameCredentialEntryList(it.key, it.value)
- }.sortedWith(
- compareByDescending{ it.sortedCredentialEntryList.first().lastUsedTimeMillis }
- )
+ // Compose sortedUserNameToCredentialEntryList
+ val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp()
+ // Sort per username
+ userNameToCredentialEntryMap.values.forEach {
+ it.sortWith(comparator)
+ }
+ // Transform to list of PerUserNameCredentialEntryLists and then sort across usernames
+ val sortedUserNameToCredentialEntryList = userNameToCredentialEntryMap.map {
+ PerUserNameCredentialEntryList(it.key, it.value)
+ }.sortedWith(
+ compareByDescending { it.sortedCredentialEntryList.first().lastUsedTimeMillis }
+ )
- return ProviderDisplayInfo(
- sortedUserNameToCredentialEntryList = sortedUserNameToCredentialEntryList,
- authenticationEntryList = authenticationEntryList,
- remoteEntry = remoteEntryList.getOrNull(0),
- )
+ return ProviderDisplayInfo(
+ sortedUserNameToCredentialEntryList = sortedUserNameToCredentialEntryList,
+ authenticationEntryList = authenticationEntryList,
+ remoteEntry = remoteEntryList.getOrNull(0),
+ )
}
private fun toActiveEntry(
- providerDisplayInfo: ProviderDisplayInfo,
+ providerDisplayInfo: ProviderDisplayInfo,
): EntryInfo? {
- val sortedUserNameToCredentialEntryList =
- providerDisplayInfo.sortedUserNameToCredentialEntryList
- val authenticationEntryList = providerDisplayInfo.authenticationEntryList
- var activeEntry: EntryInfo? = null
- if (sortedUserNameToCredentialEntryList
- .size == 1 && authenticationEntryList.isEmpty()
- ) {
- activeEntry = sortedUserNameToCredentialEntryList.first().sortedCredentialEntryList.first()
- } else if (
- sortedUserNameToCredentialEntryList
- .isEmpty() && authenticationEntryList.size == 1
- ) {
- activeEntry = authenticationEntryList.first()
- }
- return activeEntry
+ val sortedUserNameToCredentialEntryList =
+ providerDisplayInfo.sortedUserNameToCredentialEntryList
+ val authenticationEntryList = providerDisplayInfo.authenticationEntryList
+ var activeEntry: EntryInfo? = null
+ if (sortedUserNameToCredentialEntryList
+ .size == 1 && authenticationEntryList.isEmpty()
+ ) {
+ activeEntry = sortedUserNameToCredentialEntryList.first().sortedCredentialEntryList.first()
+ } else if (
+ sortedUserNameToCredentialEntryList
+ .isEmpty() && authenticationEntryList.size == 1
+ ) {
+ activeEntry = authenticationEntryList.first()
+ }
+ return activeEntry
}
private fun toGetScreenState(
- providerInfoList: List<ProviderInfo>
+ providerInfoList: List<ProviderInfo>
): GetScreenState {
- var noLocalAccount = true
- var remoteInfo: RemoteEntryInfo? = null
- providerInfoList.forEach{providerInfo -> if (
- providerInfo.credentialEntryList.isNotEmpty() || providerInfo.authenticationEntry != null
- ) { noLocalAccount = false }
- // TODO: handle the error situation that if multiple remoteInfos exists
- if (providerInfo.remoteEntry != null) {
- remoteInfo = providerInfo.remoteEntry
+ var noLocalAccount = true
+ var remoteInfo: RemoteEntryInfo? = null
+ providerInfoList.forEach { providerInfo ->
+ if (providerInfo.credentialEntryList.isNotEmpty() ||
+ providerInfo.authenticationEntry != null) {
+ noLocalAccount = false
+ }
+ // TODO: handle the error situation that if multiple remoteInfos exists
+ if (providerInfo.remoteEntry != null) {
+ remoteInfo = providerInfo.remoteEntry
+ }
}
- }
- return if (noLocalAccount && remoteInfo != null)
- GetScreenState.REMOTE_ONLY else GetScreenState.PRIMARY_SELECTION
+ return if (noLocalAccount && remoteInfo != null)
+ GetScreenState.REMOTE_ONLY else GetScreenState.PRIMARY_SELECTION
}
internal class CredentialEntryInfoComparatorByTypeThenTimestamp : Comparator<CredentialEntryInfo> {
- override fun compare(p0: CredentialEntryInfo, p1: CredentialEntryInfo): Int {
- // First prefer passkey type for its security benefits
- if (p0.credentialType != p1.credentialType) {
- if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p0.credentialType) {
- return -1
- } else if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p1.credentialType) {
- return 1
- }
- }
+ override fun compare(p0: CredentialEntryInfo, p1: CredentialEntryInfo): Int {
+ // First prefer passkey type for its security benefits
+ if (p0.credentialType != p1.credentialType) {
+ if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p0.credentialType) {
+ return -1
+ } else if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p1.credentialType) {
+ return 1
+ }
+ }
- // Then order by last used timestamp
- if (p0.lastUsedTimeMillis != null && p1.lastUsedTimeMillis != null) {
- if (p0.lastUsedTimeMillis < p1.lastUsedTimeMillis) {
- return 1
- } else if (p0.lastUsedTimeMillis > p1.lastUsedTimeMillis) {
- return -1
- }
- } else if (p0.lastUsedTimeMillis != null && p0.lastUsedTimeMillis > 0) {
- return -1
- } else if (p1.lastUsedTimeMillis != null && p1.lastUsedTimeMillis > 0) {
- return 1
+ // Then order by last used timestamp
+ if (p0.lastUsedTimeMillis != null && p1.lastUsedTimeMillis != null) {
+ if (p0.lastUsedTimeMillis < p1.lastUsedTimeMillis) {
+ return 1
+ } else if (p0.lastUsedTimeMillis > p1.lastUsedTimeMillis) {
+ return -1
+ }
+ } else if (p0.lastUsedTimeMillis != null && p0.lastUsedTimeMillis > 0) {
+ return -1
+ } else if (p1.lastUsedTimeMillis != null && p1.lastUsedTimeMillis > 0) {
+ return 1
+ }
+ return 0
}
- return 0
- }
}
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 37f2930..bc3a9c8 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Program geïnstalleer."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil jy hierdie program installeer?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil jy hierdie program opdateer?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Opdaterings vir hierdie app word tans deur <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> bestuur.\n\nAs jy opdateer, sal jy toekomstige opdaterings eerder van <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> af ontvang."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Opdaterings vir hierdie app word tans deur <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> bestuur.\n\nWil jy hierdie opdatering vanaf <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> installeer?"</string>
<string name="install_failed" msgid="5777824004474125469">"Program nie geïnstalleer nie."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die installering van die pakket is geblokkeer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Program is nie geïnstalleer nie omdat pakket met \'n bestaande pakket bots."</string>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 83966db..de53a5e 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"መተግበሪያ ተጭኗል።"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ይህን መተግበሪያ መጫን ይፈልጋሉ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ይህን መተግበሪያ ማዘመን ይፈልጋሉ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"የዚህ መተግበሪያ ዝማኔዎች አሁን በ<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> በመተዳደር ላይ ናቸው።\n\nበማዘመንዎ የወደፊት ዝማኔዎችን በምትኩ ከ<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ያገኛሉ።"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"የዚህ መተግበሪያ ዝማኔዎች አሁን በ<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> በመተዳደር ላይ ናቸው።\n\nይህን ዝማኔ ከ<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> መጫን ይፈልጋሉ።"</string>
<string name="install_failed" msgid="5777824004474125469">"መተግበሪያ አልተጫነም።"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ጥቅሉ እንዳይጫን ታግዷል።"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"እንደ ጥቅል ያልተጫነ መተግበሪያ ከነባር ጥቅል ጋር ይጋጫል።"</string>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index c7dbf08..f41115b 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"تم تثبيت التطبيق."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"هل تريد تثبيت هذا التطبيق؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"هل تريد تحديث هذا التطبيق؟"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"تتم إدارة تحديثات هذا التطبيق حاليًا من قِبل \"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>\".\n\nمن خلال التحديث، ستتلقّى التحديثات المتوفّرة من \"<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>\" بدلاً من ذلك."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"تتم إدارة تحديثات هذا التطبيق حاليًا من قِبل \"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>\".\n\nهل تريد تثبيت هذا التحديث من <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>\"؟"</string>
<string name="install_failed" msgid="5777824004474125469">"التطبيق ليس مثبتًا."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"تم حظر تثبيت الحزمة."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"لم يتم تثبيت التطبيق لأن حزمة التثبيت تتعارض مع حزمة حالية."</string>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index c456268..08758a1 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"এপ্ ইনষ্টল কৰা হ’ল।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপুনি এই এপ্টো ইনষ্টল কৰিবলৈ বিচাৰেনে?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপুনি এই এপ্টো আপডে’ট কৰিবলৈ বিচাৰেনে?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"এই এপ্টোৰ আপডে’টসমূহ বৰ্তমান <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>এ পৰিচালনা কৰি আছে।\n\nআপডে’ট কৰিলে, আপুনি ইয়াৰ পৰিবৰ্তে <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা ভৱিষ্যত আপডে’টসমূহ পাব।"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"এই এপ্টোৰ আপডে’টসমূহ বৰ্তমান <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>এ পৰিচালনা কৰি আছে।\n\nআপুনি <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা অহা এই আপডে’টটো ইনষ্টল কৰিব বিচাৰেনে?"</string>
<string name="install_failed" msgid="5777824004474125469">"এপ্ ইনষ্টল কৰা হোৱা নাই।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"পেকেজটোৰ ইনষ্টল অৱৰোধ কৰা হৈছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"এপ্টো ইনষ্টল কৰিব পৰা নগ\'ল কাৰণ ইয়াৰ সৈতে আগৰে পৰা থকা এটা পেকেজৰ সংঘাত হৈছে।"</string>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index 749254a..d6e117f 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Tətbiq quraşdırılıb."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu tətbiqi quraşdırmaq istəyirsiniz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu tətbiqi güncəlləmək istəyirsiniz?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Bu tətbiq üzrə güncəlləmələr hazırda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> tərəfindən idarə olunur.\n\nGüncəlləməklə, <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> adlı mənbədən gələcək güncəlləmələri əldə edəcəksiniz."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Bu tətbiq üzrə güncəlləmələr hazırda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> tərəfindən idarə olunur.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> adlı mənbədən bu güncəlləməni quraşdırmaq istəyirsinizmi."</string>
<string name="install_failed" msgid="5777824004474125469">"Tətbiq quraşdırılmayıb."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin quraşdırılması blok edildi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Bu paketin mövcud paket ilə ziddiyətinə görə tətbiq quraşdırılmadı."</string>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index b2943a0..13bd74b 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite da instalirate ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite da ažurirate ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Ažuriranjima ove aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAko ažurirate, buduća ažuriranja ćete dobijati od vlasnika <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Ažuriranjima ove aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nŽelite li da instalirate ovo ažuriranje vlasnika <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer je paket neusaglašen sa postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index fa64fa6..9e7a0af 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Праграма ўсталявана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Усталяваць гэту праграму?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Абнавіць гэту праграму?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Абнаўленнямі гэтай праграмы цяпер кіруе <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nВыканаўшы гэта абнаўленне, усе наступныя вы будзеце атрымліваць ад <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Абнаўленнямі гэтай праграмы цяпер кіруе <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nВы хочаце ўсталяваць гэта абнаўленне ад <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Праграма не ўсталявана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Усталяванне пакета заблакіравана."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Праграма не ўсталявана, таму што пакет канфліктуе з існуючым пакетам."</string>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index 0fb7aa5..140cd2f 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Приложението бе инсталирано."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Искате ли да инсталирате това приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Искате ли да актуализирате това приложение?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Актуализациите на това приложение понастоящем се управляват от <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nСлед актуализирането ще получавате бъдещите актуализации от <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Актуализациите на това приложение понастоящем се управляват от <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nИскате ли да инсталирате тази актуализация от <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Приложението не бе инсталирано."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирането на пакета бе блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложението не бе инсталирано, тъй като пакетът е в конфликт със съществуващ пакет."</string>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 52e5a32..ec64f9b 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"অ্যাপটি ইনস্টল করা হয়ে গেছে।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপনি কি এই অ্যাপটি ইনস্টল করতে চান?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপনি কি এই অ্যাপটি আপডেট করতে চান?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"এই অ্যাপের আপডেট বর্তমানে <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ম্যানেজ করছেন।\n\nআপডেট করা হলে, আপনি পরিবর্তে <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-এর থেকে ভবিষ্যতের আপডেট পাবেন।"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"বর্তমানে <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> এই অ্যাপের আপডেট ম্যানেজ করছেন।\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> থেকে আসা এই আপডেট ইনস্টল করতে চান।"</string>
<string name="install_failed" msgid="5777824004474125469">"অ্যাপটি ইনস্টল করা হয়নি।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ইনস্টল হওয়া থেকে প্যাকেজটিকে ব্লক করা হয়েছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"আগে থেকেই থাকা একটি প্যাকেজের সাথে প্যাকেজটির সমস্যা সৃষ্টি হওয়ায় অ্যাপটি ইনস্টল করা যায়নি।"</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index 01d160b..2f849a2 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Ažuriranjima ove aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAžuriranjem ćete dobivati buduća ažuriranja od <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Ažuriranjima ove aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nŽelite li instalirati ažuriranje od <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje ovog paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer paket nije usaglašen s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 7b42cef..9b75fe3 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"S\'ha instal·lat l\'aplicació."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vols instal·lar aquesta aplicació?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vols actualitzar aquesta aplicació?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Actualment, <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> gestiona les actualitzacions d\'aquesta aplicació.\n\nSi l\'actualitzes, obtindràs novetats de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> en el futur."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Actualment, <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> gestiona les actualitzacions d\'aquesta aplicació.\n\nVols instal·lar aquesta actualització de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"No s\'ha instal·lat l\'aplicació."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"El paquet s\'ha bloquejat perquè no es pugui instal·lar."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'aplicació no s\'ha instal·lat perquè el paquet entra en conflicte amb un d\'existent."</string>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index 7e5c881..c556952 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikace je nainstalována."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete tuto aplikaci nainstalovat?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete tuto aplikaci aktualizovat?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Aktualizace této aplikace aktuálně spravuje vlastník <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nPokud ji aktualizujete, budete místo toho v budoucnu dostávat aktualizace od vlastníka <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Aktualizace této aplikace aktuálně spravuje vlastník <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nChcete nainstalovat tuto aktualizaci od vlastníka <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikaci nelze nainstalovat."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalace balíčku byla zablokována."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikaci nelze nainstalovat, protože balíček je v konfliktu se stávajícím balíčkem."</string>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 2441f85..7f47029 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installeret."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du opdatere denne app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Opdateringer af denne app administreres i øjeblikket af <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nNår du opdaterer, vil du fremover få opdateringer fra <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> i stedet."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Opdateringer af denne app administreres i øjeblikket af <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVil du installere denne opdatering fra <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Appen blev ikke installeret."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken blev forhindret i at blive installeret."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen blev ikke installeret, da pakken er i strid med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index 24cfc55..dea95e8 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"App wurde installiert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Möchtest du diese App installieren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Möchtest du diese App aktualisieren?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Updates für diese App werden momentan von <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> verwaltet.\n\nWenn du sie aktualisierst, erhältst du zukünftige Updates stattdessen von <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Updates für diese App werden momentan von <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> verwaltet.\n\nMöchtest du dieses Update von <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> installieren?"</string>
<string name="install_failed" msgid="5777824004474125469">"App wurde nicht installiert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die Installation des Pakets wurde blockiert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Die App wurde nicht installiert, da das Paket in Konflikt mit einem bestehenden Paket steht."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index ce8356b..3c3eae8 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Η εφαρμογή εγκαταστάθηκε."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτήν την εφαρμογή;"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτήν την εφαρμογή;"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Η διαχείριση των ενημερώσεων σε αυτήν την εφαρμογή πραγματοποιείται προς το παρόν από τον κάτοχο <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nΚάνοντας την ενημέρωση, θα λαμβάνετε αντ\' αυτού τις μελλοντικές ενημερώσεις από τον κάτοχο <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Η διαχείριση των ενημερώσεων σε αυτήν την εφαρμογή πραγματοποιείται προς το παρόν από τον κάτοχο <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nΘέλετε να εγκαταστήσετε αυτήν την ενημέρωση από τον κάτοχο <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Η εφαρμογή δεν εγκαταστάθηκε."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Η εγκατάσταση του πακέτου αποκλείστηκε."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Η εφαρμογή δεν εγκαταστάθηκε, επειδή το πακέτο είναι σε διένεξη με κάποιο υπάρχον πακέτο."</string>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index b553986..9d44fcc 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Se instaló la app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Deseas instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Deseas actualizar esta app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"En este momento, las actualizaciones de esta app están administradas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nSi continúas con la actualización, recibirás actualizaciones futuras de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"En este momento, las actualizaciones de esta app están administradas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\n¿Quieres instalar esta actualización de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"No se instaló la app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se bloqueó el paquete para impedir la instalación."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"No se instaló la app debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 66e6bc3..bedb822 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplicación instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Quieres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Quieres actualizar esta aplicación?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Las actualizaciones de esta aplicación las gestiona <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nSi actualizas, recibirás las futuras actualizaciones por parte de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Las actualizaciones de esta aplicación las gestiona <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\n¿Quieres instalar esta actualización de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"No se ha instalado la aplicación."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se ha bloqueado la instalación del paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"La aplicación no se ha instalado debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index 742f663..38a6fbf 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Rakendus on installitud."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Kas soovite selle rakenduse installida?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Kas soovite seda rakendust värskendada?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Selle rakenduse värskendusi haldab praegu <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVärskendamisel saate tulevasi värskendusi hoopis omanikult <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Selle rakenduse värskendusi haldab praegu <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nKas soovite installida omaniku <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> värskenduse."</string>
<string name="install_failed" msgid="5777824004474125469">"Rakendus pole installitud."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketi installimine blokeeriti."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Rakendust ei installitud, kuna pakett on olemasoleva paketiga vastuolus."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index 4687ab5..ad2a5be 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Instalatu da aplikazioa."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Aplikazioa instalatu nahi duzu?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Aplikazioa eguneratu nahi duzu?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> arduratzen da aplikazio hau eguneratzeaz.\n\n Eguneratuz gero, hemendik aurrera <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> arduratuko da eguneratzeez."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> arduratzen da aplikazio hau eguneratzeaz.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> bidez jasotako eguneratze hau instalatu nahi duzu?"</string>
<string name="install_failed" msgid="5777824004474125469">"Ez da instalatu aplikazioa."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketea instalatzeko aukera blokeatu egin da."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Ez da instalatu aplikazioa, gatazka bat sortu delako lehendik dagoen pakete batekin."</string>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index dfe0873..2725afa 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"برنامه نصب شد."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"میخواهید این برنامه را نصب کنید؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"میخواهید این برنامه را بهروزرسانی کنید؟"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"درحالحاضر <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> بهروزرسانیهای این برنامه را مدیریت میکند.\n\nبا بهروز کردن، بهروزرسانیهای آتی را بهجای مالک قبلی از <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> دریافت خواهید کرد."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"درحالحاضر <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> بهروزرسانیهای این برنامه را مدیریت میکند.\n\nمیخواهید این بهروزرسانی را از <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> نصب کنید؟"</string>
<string name="install_failed" msgid="5777824004474125469">"برنامه نصب نشد."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"از نصب شدن بسته جلوگیری شد."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"برنامه نصب نشد چون بسته با بسته موجود تداخل دارد."</string>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index 9a76c91..0a7486d 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Sovellus on asennettu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Haluatko asentaa tämän sovelluksen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Haluatko päivittää tämän sovelluksen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> hallitsee tämän sovelluksen päivityksiä.\n\nPäivittämisen jälkeen päivityksiä hallitsee <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> hallitsee tämän sovelluksen päivityksiä.\n\nHaluatko ladata tämän päivityksen täältä: <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Sovellusta ei asennettu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin asennus estettiin."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Sovellusta ei asennettu, koska paketti on ristiriidassa nykyisen paketin kanssa."</string>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 9be6f5a..1377f25 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette application?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette application?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Les mises à jour pour cette application sont actuellement gérées par <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nEn effectuant une mise à jour, vous recevrez plutôt les futures mises à jour de la part de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Les mises à jour de cette application sont actuellement gérées par <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVoulez-vous installer cette mise à jour de la part de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du paquet a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 7744fabe..5eaea19 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Les mises à jour de cette appli sont actuellement gérées par <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nEn procédant à la mise à jour, vous recevrez les futures mises à jour de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> à la place."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Les mises à jour de cette appli sont actuellement gérées par <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVoulez-vous installer cette mise à jour de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ?"</string>
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du package a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le package est en conflit avec un package déjà présent."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index 6ba8813..205cb26 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Queres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Queres actualizar esta aplicación?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Actualmente, as actualizacións desta aplicación xestiónaas <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nSe a actualizas, as futuras actualizacións recibiralas de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Actualmente, as actualizacións desta aplicación xestiónaas <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nQueres instalar esta actualización de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Non se instalou a aplicación"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Bloqueouse a instalación do paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A aplicación non se instalou porque o paquete presenta un conflito cun paquete que xa hai."</string>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index d139b2b..ab752e6 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"શું તમે આ ઍપ ઇન્સ્ટૉલ કરવા માગો છો?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"શું તમે આ ઍપ અપડેટ કરવા માગો છો?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"આ ઍપની અપડેટને હાલમાં <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે.\n\nઅપડેટ કરવાથી, તમને તેના બદલે <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> તરફથી ભવિષ્યની અપડેટ પ્રાપ્ત થશે."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"આ ઍપની અપડેટને હાલમાં <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે.\n\nશું તમે <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> તરફથી આ અપડેટ ઇન્સ્ટૉલ કરવા માગો છો."</string>
<string name="install_failed" msgid="5777824004474125469">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી નથી."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"પૅકેજને ઇન્સ્ટૉલ થવાથી બ્લૉક કરવામાં આવ્યું હતું."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"પૅકેજનો અસ્તિત્વમાંના પૅકેજ સાથે વિરોધાભાસ હોવાને કારણે ઍપ્લિકેશન ઇન્સ્ટૉલ થઈ નથી."</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index 17cf962..3bb636d 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ऐप्लिकेशन इंस्टॉल हो गया."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"क्या आपको यह ऐप्लिकेशन इंस्टॉल करना है?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"क्या आप इस ऐप्लिकेशन को अपडेट करना चाहते हैं?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"फ़िलहाल, इस ऐप्लिकेशन के अपडेट <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> मैनेज करता है.\n\nऐप्लिकेशन अपडेट करने के बाद, नए अपडेट <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> से मिलेंगे."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"फ़िलहाल, इस ऐप्लिकेशन के अपडेट <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> मैनेज करता है.\n\nक्या यह अपडेट <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> से करवाना है."</string>
<string name="install_failed" msgid="5777824004474125469">"ऐप्लिकेशन इंस्टॉल नहीं हुआ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पैकेज को इंस्टॉल होने से ब्लॉक किया हुआ है."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ऐप्लिकेशन इंस्टॉल नहीं हुआ क्योंकि पैकेज का किसी मौजूदा पैकेज से विरोध है."</string>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index 9b7eeea..2eb3434 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Ažuriranjima ove aplikacije trenutačno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAko je ažurirate, buduća ažuriranja primat ćete od vlasnika <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Ažuriranjima ove aplikacije trenutačno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nŽelite li instalirati ažuriranje od vlasnika <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa blokirano je."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija koja nije instalirana kao paket u sukobu je s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index 10e79a6..fc2d34b 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Alkalmazás telepítve."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Telepíti ezt az alkalmazást?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Frissíti ezt az alkalmazást?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Az alkalmazást érintő frissítéseket jelenleg <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> kezeli.\n\nA mostani frissítés után a jövőbeli frissítéseket helyette tőle érkeznek majd: <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Az alkalmazást érintő frissítéseket jelenleg <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> kezeli.\n\nSzeretné telepíteni a tőle származó frissítést: <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Az alkalmazás nincs telepítve."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A csomag telepítését letiltotta a rendszer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A nem csomagként telepített alkalmazás ütközik egy már létező csomaggal."</string>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index 0b46090..8a6f3af 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Հավելվածը տեղադրված է:"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Տեղադրե՞լ այս հավելվածը:"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Թարմացնե՞լ այս հավելվածը։"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Այս հավելվածի թարմացումները ներկայումս կառավարվում են <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>-ի կողմից։\n\nԹարմացնելով՝ դուք հետագայում թարմացումներ կստանաք <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-ից։"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Այս հավելվածի թարմացումները ներկայումս կառավարվում են <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>-ի կողմից։\n\nՈւզո՞ւմ եք տեղադրել այս թարմացումը <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-ից։"</string>
<string name="install_failed" msgid="5777824004474125469">"Հավելվածը տեղադրված չէ:"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Փաթեթի տեղադրումն արգելափակվել է:"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Հավելվածը չի տեղադրվել, քանի որ տեղադրման փաթեթն ունի հակասություն առկա փաթեթի հետ:"</string>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index ed25528..56b47ad 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi terinstal."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingin menginstal aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingin mengupdate aplikasi ini?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Update aplikasi ini sekarang dikelola oleh <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nDengan mengupdate, Anda akan mendapatkan update mendatang dari <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Update aplikasi ini sekarang dikelola oleh <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nIngin menginstal update ini dari <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak terinstal."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paket diblokir sehingga tidak dapat diinstal."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikasi tidak diinstal karena paket ini bentrok dengan paket yang sudah ada."</string>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index 0c35415..08fa6a0 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Forritið er uppsett."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Viltu setja upp þetta forrit?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Viltu uppfæra þetta forrit?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> stjórnar uppfærslum þessa forrits eins og er.\n\nMeð því að uppfæra færðu síðari uppfærslur frá <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> í staðinn."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> stjórnar uppfærslum þessa forrits eins og er.\n\nViltu setja upp þessa uppfærslu frá <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Forritið er ekki uppsett."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Lokað var á uppsetningu pakkans."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Forritið var ekki sett upp vegna árekstra á milli pakkans og annars pakka."</string>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index bfc1e03..939b1f4 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"App installata."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vuoi installare questa app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vuoi aggiornare questa app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Gli aggiornamenti a questa app sono attualmente gestiti da <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nEseguendo l\'aggiornamento, gli aggiornamenti futuri saranno forniti invece da <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Gli aggiornamenti a questa app sono attualmente gestiti da <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVuoi installare questo aggiornamento da <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"App non installata."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"È stata bloccata l\'installazione del pacchetto."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App non installata poiché il pacchetto è in conflitto con un pacchetto esistente."</string>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 0cd7b30..906043f 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"האפליקציה הותקנה."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"האם ברצונך להתקין אפליקציה זו?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"האם ברצונך לעדכן אפליקציה זו?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"העדכונים של האפליקציה הזו מנוהלים כרגע על ידי <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nלאחר העדכון הנוכחי, העדכונים העתידיים ינוהלו על ידי <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> במקום זאת."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"העדכונים של האפליקציה הזו מנוהלים כרגע על ידי <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nלהתקין את העדכון הזה של <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"האפליקציה לא הותקנה."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"החבילה נחסמה להתקנה."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"האפליקציה לא הותקנה כי החבילה מתנגשת עם חבילה קיימת."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 47e295a..d114bb2 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"アプリをインストールしました。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"このアプリをインストールしますか?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"このアプリを更新しますか?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"このアプリのアップデートは現在 <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> によって管理されています。\n\n更新すると、今後は代わりに <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> からアップデートを入手するようになります。"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"このアプリのアップデートは現在 <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> によって管理されています。\n\nこのアップデートを <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> からインストールしますか?"</string>
<string name="install_failed" msgid="5777824004474125469">"アプリはインストールされていません。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"パッケージのインストールはブロックされています。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"パッケージが既存のパッケージと競合するため、アプリをインストールできませんでした。"</string>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index 56b79f6..82ca5a7 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"აპი დაინსტალირებულია."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"გნებავთ ამ აპის დაყენება?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"გსურთ ამ აპის განახლება?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ამ აპის განახლებებს ამჟამად მართავს <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nგანახლებით მომავალ განახლებებს მიიღებთ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-გან."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ამ აპის განახლებებს ამჟამად მართავს <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nგსურთ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-გან განახლების ინსტალაცია?"</string>
<string name="install_failed" msgid="5777824004474125469">"აპი დაუინსტალირებელია."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ამ პაკეტის ინსტალაცია დაბლოკილია."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"აპი ვერ დაინსტალირდა, რადგან პაკეტი კონფლიქტშია არსებულ პაკეტთან."</string>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index d6ce0ce..562898d 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Қолданба орнатылды."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бұл қолданбаны орнатқыңыз келе ме?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бұл қолданбаны жаңартқыңыз келе ме?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Бұл қолданбаны жаңартуды қазір <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> басқарады.\n\nЖаңартсаңыз, келесі жаңартуды <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> беретін болады."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Бұл қолданбаны жаңартуды қазір <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> басқарады.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> беретін жаңартуды пайдаланғыңыз келе ме?"</string>
<string name="install_failed" msgid="5777824004474125469">"Қолданба орнатылмады."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Пакетті орнатуға тыйым салынды."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Жаңа пакет пен бұрыннан бар пакеттің арасында қайшылық туындағандықтан, қолданба орнатылмады."</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 7efe082..938aa3be 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"បានដំឡើងកម្មវិធី។"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"តើអ្នកចង់ដំឡើងកម្មវិធីនេះដែរទេ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"តើអ្នកចង់ដំឡើងកំណែកម្មវិធីនេះដែរទេ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"បច្ចុប្បន្ន ការដំឡើងកំណែកម្មវិធីនេះត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>។\n\nតាមរយៈការដំឡើងកំណែ អ្នកនឹងទទួលបានកំណែថ្មីៗនៅពេលក្រោយពី <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ជំនួសវិញ។"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"បច្ចុប្បន្ន ការដំឡើងកំណែកម្មវិធីនេះត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>។\n\nតើអ្នកចង់ដំឡើងកំណែថ្មីនេះពី <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ឬ។"</string>
<string name="install_failed" msgid="5777824004474125469">"មិនបានដំឡើងកម្មវិធីទេ។"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"កញ្ចប់ត្រូវបានទប់ស្កាត់មិនឱ្យដំឡើង។"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"កម្មវិធីមិនបានដំឡើងទេ ដោយសារកញ្ចប់កម្មវិធីមិនត្រូវគ្នាជាមួយកញ្ចប់ដែលមានស្រាប់។"</string>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 57a9b64a..e70d75d 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ಈ ಆ್ಯಪ್ನ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಪ್ರಸ್ತುತ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ಅವರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ.\n\nಅಪ್ಡೇಟ್ ಮಾಡುವುದರಿಂದ, ಬದಲಿಗೆ ನೀವು ಭವಿಷ್ಯದ ಅಪ್ಡೇಟ್ಗಳನ್ನು <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ಅವರಿಂದ ಪಡೆಯುತ್ತೀರಿ."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ಈ ಆ್ಯಪ್ನ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಪ್ರಸ್ತುತ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ಅವರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ.\n\nನೀವು <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ಅವರ ಈ ಅಪ್ಡೇಟ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ."</string>
<string name="install_failed" msgid="5777824004474125469">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿಲ್ಲ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ಪ್ಯಾಕೇಜ್ನಂತೆ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿರುವ ಆ್ಯಪ್ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೇಜ್ ಜೊತೆಗೆ ಸಂಘರ್ಷವಾಗುತ್ತದೆ."</string>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index dbc7bc8..b5adf3f 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"앱이 설치되었습니다."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"이 앱을 설치하시겠습니까?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"이 앱을 업데이트하시겠습니까?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"이 앱 업데이트는 현재 <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>에서 관리합니다.\n\n업데이트할 경우 대신 <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>에서 향후 업데이트를 제공합니다."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"이 앱 업데이트는 현재 <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>에서 관리합니다.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>에서 제공하는 업데이트를 설치하시겠습니까?"</string>
<string name="install_failed" msgid="5777824004474125469">"앱이 설치되지 않았습니다."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"패키지 설치가 차단되었습니다."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"패키지가 기존 패키지와 충돌하여 앱이 설치되지 않았습니다."</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index 614fbaf..34c6293 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Колдонмо орнотулду."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бул колдонмону орнотоюн деп жатасызбы?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бул колдонмону жаңыртайын деп жатасызбы?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Бул колдонмонун жаңыртууларын учурда <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> тескеп жатат.\n\nЖаңыртуу менен келечектеги жаңыртууларды анын ордуна <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> жөнөтүп калат."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Бул колдонмонун жаңыртууларын учурда <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> тескеп жатат.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> жөнөткөн жаңыртуунун чыгарып саласызбы?"</string>
<string name="install_failed" msgid="5777824004474125469">"Колдонмо орнотулган жок."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Топтомду орнотууга болбойт."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Башка топтом менен дал келбегендиктен колдонмо орнотулган жок."</string>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index d8779e7..45cd47a 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ຕິດຕັ້ງແອັບແລ້ວ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ທ່ານຕ້ອງການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ທ່ານຕ້ອງການອັບເດດແອັບນີ້ບໍ່?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ໃນຕອນນີ້ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ເປັນຜູ້ຈັດການການອັບເດດແອັບນີ້.\n\nຫາກອັບເດດ, ທ່ານຈະໄດ້ຮັບການອັບເດດໃນອະນາຄົດຈາກ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ແທນ."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ໃນຕອນນີ້ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ເປັນຜູ້ຈັດການການອັບເດດແອັບນີ້.\n\nທ່ານຕ້ອງການຕິດຕັ້ງການອັບເດດນີ້ຈາກ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ຫຼືບໍ່."</string>
<string name="install_failed" msgid="5777824004474125469">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເທື່ອ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ແພັກເກດຖືກບລັອກບໍ່ໃຫ້ໄດ້ຮັບການຕິດຕັ້ງ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເນື່ອງຈາກແພັກເກດຂັດແຍ່ງກັບແພັກເກດທີ່ມີຢູ່ກ່ອນແລ້ວ."</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index 8b011be..b802fa2 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Lietotne ir instalēta."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vai vēlaties instalēt šo lietotni?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vai vēlaties atjaunināt šo lietotni?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Šīs lietotnes atjauninājumus pašlaik pārvalda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nJa veiksiet atjaunināšanu, turpmākos atjauninājumus nodrošinās <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Šīs lietotnes atjauninājumus pašlaik pārvalda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVai vēlaties instalēt atjauninājumu, ko nodrošina <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Lietotne nav instalēta."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakotnes instalēšana tika bloķēta."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Lietotne netika instalēta, jo pastāv pakotnes konflikts ar esošu pakotni."</string>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index 3c681e9..c038506 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Апликацијата е инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Дали сакате да ја инсталирате апликацијава?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Дали сакате да ја ажурирате апликацијава?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Ажурирањата на апликацијава тековно се управуваат од <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nСо ажурирање, ќе добивате ажурирања во иднината од <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Ажурирањата на апликацијава тековно се управуваат од <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nДали сакате да го инсталирате ажурирањево од <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Апликацијата не е инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирањето на пакетот е блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација што не е инсталирана како пакет е во конфликт со постоечки пакет."</string>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index aa3aac0..68bb819 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തു."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ഈ ആപ്പിലെ അപ്ഡേറ്റുകൾ നിലവിൽ മാനേജ് ചെയ്യുന്നത് <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ആണ്.\n\nഅപ്ഡേറ്റ് ചെയ്യുന്നതിലൂടെ, പകരം നിങ്ങൾക്ക് ഭാവി അപ്ഡേറ്റുകൾ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> എന്നയാളിൽ നിന്ന് ലഭിക്കും."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ഈ ആപ്പിലെ അപ്ഡേറ്റുകൾ നിലവിൽ മാനേജ് ചെയ്യുന്നത് <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ആണ്.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> എന്നയാളിൽ നിന്ന് ഈ അപ്ഡേറ്റ് ഇൻസ്റ്റാൾ ചെയ്യാൻ നിങ്ങൾ താൽപ്പര്യപ്പെടുന്നുണ്ടോ."</string>
<string name="install_failed" msgid="5777824004474125469">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"പാക്കേജ് ഇൻസ്റ്റാൾ ചെയ്യുന്നത് ബ്ലോക്ക് ചെയ്തു."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"പാക്കേജിന് നിലവിലുള്ള പാക്കേജുമായി പൊരുത്തക്കേടുള്ളതിനാൽ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തില്ല."</string>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index 112e2f1..6a95f54 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Аппыг суулгасан."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Та энэ аппыг суулгахыг хүсэж байна уу?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Та энэ аппыг шинэчлэхийг хүсэж байна уу?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Энэ аппын шинэчлэлтийг одоогоор <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>-с удирддаг.\n\nШинэчилснээр та цаашдын шинэчлэлтийг оронд нь <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-с авна."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Энэ аппын шинэчлэлтийг одоогоор <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>-с удирддаг.\n\nТа <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>-н энэ шинэчлэлтийг суулгахыг хүсэж байна уу?"</string>
<string name="install_failed" msgid="5777824004474125469">"Аппыг суулгаагүй."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Багц суулгахыг блоклосон байна."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Багц одоо байгаа багцтай тохирохгүй байгаа тул аппыг суулгаж чадсангүй."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 5a79715..fb271b3 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तुम्हाला हे ॲप इंस्टॉल करायचे आहे का?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तुम्हाला हे ॲप अपडेट करायचे आहे का?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"या अॅपसाठीचे अपडेट सध्या <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> द्वारे व्यवस्थापित केले जात आहेत.\n\nत्या ऐवजी, अपडेट केल्याने, तुम्हाला भविष्यातील अपडेट <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> कडून मिळतील."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"या अॅपसाठीचे अपडेट सध्या <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> द्वारे व्यवस्थापित केले जात आहेत.\n\nतुम्हाला हे अपडेट <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> कडून इंस्टॉल करायचे आहे का."</string>
<string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 8d5e25f..4e9daa7 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi dipasang."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Adakah anda ingin memasang aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Adakah anda mahu mengemas kini apl ini?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Kemaskinian pada apl ini diuruskan oleh <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> pada masa ini.\n\nDengan membuat pengemaskinian, anda akan mendapat kemaskinian akan datang daripada <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Kemaskinian pada apl ini diuruskan oleh <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> pada masa ini.\n\nAdakah anda mahu memasang kemaskinian ini daripada <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak dipasang."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakej ini telah disekat daripada dipasang."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Apl tidak dipasang kerana pakej bercanggah dengan pakej yang sedia ada."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index a9ac033..35e82fe 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ။"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ဤအက်ပ်ကို ထည့်သွင်းလိုသလား။"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ဤအက်ပ်ကို အပ်ဒိတ်လုပ်လိုသလား။"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ဤအက်ပ်ရှိ အပ်ဒိတ်များကို လောလောဆယ်တွင် <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> က စီမံထားသည်။\n\n၎င်းအစား အပ်ဒိတ်လုပ်ခြင်းဖြင့် <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ထံမှ နောက်အပ်ဒိတ်များ ရရှိပါမည်။"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ဤအက်ပ်ရှိ အပ်ဒိတ်များကို လောလောဆယ်တွင် <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> က စီမံထားသည်။\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ထံမှ ဤအပ်ဒိတ်ကို ထည့်သွင်းလိုပါသလား။"</string>
<string name="install_failed" msgid="5777824004474125469">"အက်ပ်မထည့်သွင်းရသေးပါ"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ပက်ကေ့ဂျ်ထည့်သွင်းခြင်းကို ပိတ်ထားသည်။"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ပက်ကေ့ဂျ်အဖြစ် ထည့်သွင်းမထားသော အက်ပ်သည် လက်ရှိပက်ကေ့ဂျ်နှင့် တိုက်နေသည်။"</string>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index 5f70b9d..3b145d1 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du oppdatere denne appen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Oppdateringer for denne appen administreres nå av <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVed å oppdatere får du fremtidige oppdateringer fra <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> i stedet."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Oppdateringer for denne appen administreres nå av <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVil du installere denne oppdateringen fra <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Appen ble ikke installert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken er blokkert fra å bli installert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen ble ikke installert fordi pakken er i konflikt med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index e7e03a4..4efd35a 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"एप इन्स्टल गरियो।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तपाईं यो एप इन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तपाईं यो एप अपडेट गर्न चाहनुहुन्छ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ले हाल यो एपका अपडेटहरू व्यवस्थापन गर्छ।\n\nतपाईंले अपडेट गर्नुभयो भने तपाईं भविष्यमा <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> बाट अपडेटहरू प्राप्त गर्नु हुने छ।"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ले हाल यो एपका अपडेटहरू व्यवस्थापन गर्छ।\n\nतपाईं <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ले उपलब्ध गराएको यो अपडेट इन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index a859861..3e85971 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"App geïnstalleerd."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil je deze app installeren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil je deze app updaten?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Updates voor deze app worden momenteel beheerd door <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAls je updatet, krijg je volgende updates in plaats daarvan van <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Updates voor deze app worden momenteel beheerd door <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nWil je deze update van <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> installeren?"</string>
<string name="install_failed" msgid="5777824004474125469">"App niet geïnstalleerd."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"De installatie van het pakket is geblokkeerd."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App die niet is geïnstalleerd als pakket conflicteert met een bestaand pakket."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 5131a11..f457a2d 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ଆପ ଇନଷ୍ଟଲ ହୋଇଗଲା।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ଆପଣ ଏହି ଆପକୁ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ଆପଣ ଏହି ଆପକୁ ଅପଡେଟ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ଏହି ଆପରେ ଅପଡେଟଗୁଡ଼ିକ ବର୍ତ୍ତମାନ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି।\n\nଅପଡେଟ କରି, ଆପଣ ଏହା ପରିବର୍ତ୍ତେ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଭବିଷ୍ୟତର ଅପଡେଟଗୁଡ଼ିକ ପାଇବେ।"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ଏହି ଆପରେ ଅପଡେଟଗୁଡ଼ିକ ବର୍ତ୍ତମାନ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି।\n\nଆପଣ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଏହି ଅପଡେଟ ଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି?"</string>
<string name="install_failed" msgid="5777824004474125469">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ଏହି ପ୍ୟାକେଜ୍କୁ ଇନଷ୍ଟଲ୍ କରାଯିବାରୁ ଅବରୋଧ କରାଯାଇଥିଲା।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ପୂର୍ବରୁ ଥିବା ପ୍ୟାକେଜ୍ ସହ ଏହି ପ୍ୟାକେଜ୍ର ସମସ୍ୟା ଉପୁଯିବାରୁ ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇପାରିଲା ନାହିଁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 34373f9..e8977d1 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ਐਪ ਸਥਾਪਤ ਕੀਤੀ ਗਈ।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ਫ਼ਿਲਹਾਲ ਇਸ ਐਪ ਦੇ ਅੱਪਡੇਟਾਂ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n\nਅੱਪਡੇਟ ਕਰਨ ਨਾਲ, ਇਸਦੀ ਬਜਾਏ ਤੁਹਾਨੂੰ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ਤੋਂ ਭਵਿੱਖੀ ਅੱਪਡੇਟ ਪ੍ਰਾਪਤ ਹੋਣਗੇ।"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ਫ਼ਿਲਹਾਲ ਇਸ ਐਪ ਦੇ ਅੱਪਡੇਟਾਂ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n\nਕੀ ਤੁਸੀਂ <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ਵੱਲੋਂ ਇਸ ਅੱਪਡੇਟ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ।"</string>
<string name="install_failed" msgid="5777824004474125469">"ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ਪੈਕੇਜ ਨੂੰ ਸਥਾਪਤ ਹੋਣ ਤੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ਪੈਕੇਜ ਦੇ ਇੱਕ ਮੌਜੂਦਾ ਪੈਕੇਜ ਨਾਲ ਵਿਵਾਦ ਹੋਣ ਕਰਕੇ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index 6626f39..e06dea6 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacja została zainstalowana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Zainstalować tę aplikację?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Zaktualizować tę aplikację?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Aktualizacjami tej aplikacji zarządza obecnie <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nJeśli pobierzesz aktualizację, przyszłe aktualizacje będzie zapewniać <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Aktualizacjami tej aplikacji zarządza obecnie <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nChcesz zainstalować tę aktualizację ze źródła <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacja nie została zainstalowana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalacja pakietu została zablokowana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacja nie została zainstalowana, bo powoduje konflikt z istniejącym pakietem."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 51f94e2..98a75cf 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"No momento, as atualizações deste app são gerenciadas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAo atualizar, você receberá as atualizações futuras de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"No momento, as atualizações deste app são gerenciadas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nGostaria de instalar esta atualização de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 51f94e2..98a75cf 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"No momento, as atualizações deste app são gerenciadas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAo atualizar, você receberá as atualizações futuras de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"No momento, as atualizações deste app são gerenciadas por <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nGostaria de instalar esta atualização de <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index 0de0ac0..7a18b2a 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplicație instalată."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vrei să instalezi această aplicație?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vrei să actualizezi această aplicație?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Actualizările acestei aplicații sunt gestionate de <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nDacă actualizezi, vei primi actualizări de la <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Actualizările acestei aplicații sunt gestionate de <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVrei să instalezi această actualizare de la <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicația nu a fost instalată."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalarea pachetului a fost blocată."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplicația nu a fost instalată deoarece pachetul intră în conflict cu un pachet existent."</string>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index 106d325..3bc40c3 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Приложение установлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установить приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Обновить приложение?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"В настоящее время обновлениями этого приложения управляет <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nЕсли вы установите обновление, то все последующие будете получать от <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"В настоящее время обновлениями этого приложения управляет <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nВы хотите установить это обновление от <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Приложение не установлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Установка пакета заблокирована."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложение не установлено, так как оно конфликтует с другим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index e2880eb..9d400ef 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"යෙදුම ස්ථාපනය කර ඇත."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"මෙම යෙදුම ස්ථාපනය කිරීමට ඔබට අවශ්යද?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ඔබට මෙම යෙදුම යාවත්කාලීන කිරීමට අවශ්යද?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"මෙම යෙදුම වෙත යාවත්කාලීන කිරීම් දැනට <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> විසින් කළමනාකරණය කරනු ලැබේ.\n\nයාවත්කාලීන කිරීමෙන්, ඔබට <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> වෙතින් අනාගත යාවත්කාලීන ලැබෙනු ඇත."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"මෙම යෙදුම වෙත යාවත්කාලීන කිරීම් දැනට <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> විසින් කළමනාකරණය කරනු ලැබේ.\n\nඔබට <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> වෙතින් මෙම යාවත්කාලීනය ස්ථාපනය කිරීමට අවශ්ය ද?"</string>
<string name="install_failed" msgid="5777824004474125469">"යෙදුම ස්ථාපනය කර නැත."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"මෙම පැකේජය ස්ථාපනය කිරීම අවහිර කරන ලදි."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"පැකේජය දැනට පවතින පැකේජයක් සමග ගැටෙන නිසා යෙදුම ස්ථාපනය නොකරන ලදී."</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index b5ecf78..cb3cdae 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikácia bola nainštalovaná."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete túto aplikáciu nainštalovať?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete túto aplikáciu aktualizovať?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Aktualizácie tejto aplikácie momentálne spravuje vlastník <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nPo aktualizovaní budete namiesto toho získavať budúce aplikácie od vlastníka <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Aktualizácie tejto aplikácie momentálne spravuje vlastník <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nChcete túto aktualizáciu nainštalovať od vlastníka <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikácia nebola nainštalovaná."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Inštalácia balíka bola zablokovaná."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikácia sa nenainštalovala, pretože balík je v konflikte s existujúcim balíkom."</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index fe4e717..654fba1 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je nameščena."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ali želite namestiti to aplikacijo?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ali želite posodobiti to aplikacijo?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Posodobitve te aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nČe posodobite, bo pošiljatelj prihodnjih posodobitev <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Posodobitve te aplikacije trenutno upravlja <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nAli želite namestiti to posodobitev, ki jo je poslal <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija ni nameščena."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Namestitev paketa je bila blokirana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija ni bila nameščena, ker je paket v navzkrižju z obstoječim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index b52bccd..b967259 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacioni u instalua."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Dëshiron ta instalosh këtë aplikacion?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Dëshiron ta përditësosh këtë aplikacion?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Përditësimet për këtë aplikacion menaxhohen aktualisht nga <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nDuke e përditësuar, përditësimet në të ardhmen do t\'i marrësh nga <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Përditësimet për këtë aplikacion menaxhohen aktualisht nga <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nDëshiron ta instalosh këtë përditësim nga <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacioni nuk u instalua."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalimi paketës u bllokua."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacioni nuk u instalua pasi paketa është në konflikt me një paketë ekzistuese."</string>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index 19c77ce..8858ef5 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Апликација је инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Желите да инсталирате ову апликацију?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Желите да ажурирате ову апликацију?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Ажурирањима ове апликације тренутно управља <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nАко ажурирате, будућа ажурирања ћете добијати од власника <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Ажурирањима ове апликације тренутно управља <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nЖелите ли да инсталирате ово ажурирање власника <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Апликација није инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирање пакета је блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација није инсталирана јер је пакет неусаглашен са постојећим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index 351e3f8..43f3d4c 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Appen har installerats."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vill du installera den här appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vill du uppdatera den här appen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Uppdateringar av den här appen hanteras för närvarande av <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nNär du uppdaterar får du i stället uppdateringar från <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Uppdateringar av den här appen hanteras för närvarande av <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nVill du installera den här uppdateringen från <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Appen har inte installerats."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketet har blockerats för installation."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen har inte installerats på grund av en konflikt mellan detta paket och ett befintligt paket."</string>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index b7ffc29..978f667 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Imesakinisha programu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ungependa kusakinisha programu hii?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ungependa kusasisha programu hii?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Masasisho ya programu hii kwa sasa yanadhibitiwa na <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nKwa kusasisha, utapata masasisho yajayo kutoka kwa <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> badala yake."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Masasisho ya programu hii kwa sasa yanasimamiwa na <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>\n\nJe, ungependa kusakinisha sasisho hili kutoka kwa <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Imeshindwa kusakinisha programu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Kifurushi kimezuiwa kisisakinishwe."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Programu haikusakinishwa kwa sababu kifurushi kinakinzana na kifurushi kingine kilichopo."</string>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index ad0c9a0..eaa8711 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ஆப்ஸ் நிறுவப்பட்டது."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"இந்த ஆப்ஸை நிறுவ வேண்டுமா?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"இந்த ஆப்ஸுக்கான புதுப்பிப்புகள் தற்போது <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> மூலம் நிர்வகிக்கப்படுகின்றன.\n\nபுதுப்பிப்பதன் மூலம் இனிவரும் புதுப்பிப்புகளை <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> மூலம் பெறுவீர்கள்."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"இந்த ஆப்ஸுக்கான புதுப்பிப்புகள் தற்போது <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> மூலம் நிர்வகிக்கப்படுகின்றன.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> மூலம் இந்தப் புதுப்பிப்பை நிறுவ விரும்புகிறீர்களா?"</string>
<string name="install_failed" msgid="5777824004474125469">"ஆப்ஸ் நிறுவப்படவில்லை."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"இந்தத் தொகுப்பு நிறுவப்படுவதிலிருந்து தடுக்கப்பட்டது."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"இந்தத் தொகுப்பு ஏற்கனவே உள்ள தொகுப்புடன் முரண்படுவதால் ஆப்ஸ் நிறுவப்படவில்லை."</string>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 6ab13dc..a6cd3e7 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"యాప్ ఇన్స్టాల్ చేయబడింది."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"మీరు ఈ యాప్ను ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"మీరు ఈ యాప్ను అప్డేట్ చేయాలనుకుంటున్నారా?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ఈ యాప్కి అప్డేట్లు ప్రస్తుతం <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ద్వారా మేనేజ్ చేయబడుతున్నాయి.\n\nఅప్డేట్ చేయడం ద్వారా, మీరు అందుకు బదులుగా <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> నుండి భవిష్యత్తు అప్డేట్లను పొందుతారు."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ఈ యాప్కి అప్డేట్లు ప్రస్తుతం<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ద్వారా మేనేజ్ చేయబడుతున్నాయి.\n\nమీరు <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> నుండి ఈ అప్డేట్ను ఇన్స్టాల్ చేయాలనుకుంటున్నారా."</string>
<string name="install_failed" msgid="5777824004474125469">"యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ప్యాకేజీ ఇన్స్టాల్ కాకుండా బ్లాక్ చేయబడింది."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ప్యాకేజీ, అలాగే ఇప్పటికే ఉన్న ప్యాకేజీ మధ్య వైరుధ్యం ఉన్నందున యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index 0e7274b..fd1af0b 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"ติดตั้งแอปแล้ว"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"คุณต้องการติดตั้งแอปนี้ไหม"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"คุณต้องการอัปเดตแอปนี้ไหม"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"ขณะนี้ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> เป็นผู้จัดการการอัปเดตแอปนี้\n\nหากอัปเดต คุณจะได้รับการอัปเดตในอนาคตจาก <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> แทน"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"ขณะนี้ <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> เป็นผู้จัดการการอัปเดตแอปนี้\n\nคุณต้องการติดตั้งการอัปเดตนี้จาก <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> ไหม"</string>
<string name="install_failed" msgid="5777824004474125469">"ไม่ได้ติดตั้งแอป"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"มีการบล็อกแพ็กเกจไม่ให้ติดตั้ง"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ไม่ได้ติดตั้งแอปเพราะแพ็กเกจขัดแย้งกับแพ็กเกจที่มีอยู่"</string>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 5f480bc..f46be7f 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Na-install na ang app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Gusto mo bang i-install ang app na ito?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Gusto mo bang i-update ang app na ito?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Kasalukuyang pinamamahalaan ng <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ang mga update sa app na ito.\n\nSa pamamagitan ng pag-update, makakakuha ka na lang ng mga update sa hinaharap mula sa <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Kasalukuyang pinamamahalaan ng <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> ang mga update sa app na ito.\n\nGusto mo bang i-install ang update na ito mula sa <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Hindi na-install ang app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Na-block ang pag-install sa package."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Hindi na-install ang app dahil nagkakaproblema ang package sa isang dati nang package."</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 7eacad0..7548c5d 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Uygulama yüklendi."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu uygulamayı yüklemek istiyor musunuz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu uygulamayı güncellemek istiyor musunuz?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Bu uygulamadaki güncellemeler şu anda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> tarafından yönetiliyor.\n\nUygulamayı güncellerseniz bundan sonraki güncellemeleri <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> gönderecektir."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Bu uygulamadaki güncellemeler şu anda <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> tarafından yönetiliyor.\n\n<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> tarafından gönderilen bu güncellemeyi yüklemek istiyor musunuz?"</string>
<string name="install_failed" msgid="5777824004474125469">"Uygulama yüklenmedi."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin yüklemesi engellendi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Paket, mevcut bir paketle çakıştığından uygulama yüklenemedi."</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index e94c716..48ff554 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Програму встановлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установити цей додаток?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Оновити цей додаток?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Оновленнями для цього додатка наразі керує <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nОновивши його зараз, ви надалі отримуватимете оновлення від <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Оновленнями для цього додатка наразі керує <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nУстановити це оновлення від <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>?"</string>
<string name="install_failed" msgid="5777824004474125469">"Програму не встановлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Встановлення пакета заблоковано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Додаток не встановлено, оскільки пакет конфліктує з наявним пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index 234cd2a..2d49c9b 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Ứng dụng đã được cài đặt."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bạn có muốn cài đặt ứng dụng này không?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bạn có muốn cập nhật ứng dụng này không?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Hiện tại, <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> đang quản lý các bản cập nhật của ứng dụng này.\n\nBằng việc cập nhật, bạn sẽ nhận được các bản cập nhật sau này của <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Hiện tại, <xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g> đang quản lý các bản cập nhật của ứng dụng này.\n\nBạn có muốn cài đặt bản cập nhật này của <xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> không?"</string>
<string name="install_failed" msgid="5777824004474125469">"Ứng dụng chưa được cài đặt."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Đã chặn cài đặt gói."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Chưa cài đặt được ứng dụng do gói xung đột với một gói hiện có."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index 737bf23..eb13321 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"已安装应用。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安装此应用吗?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此应用吗?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"此应用的更新目前由<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>管理。\n\n更新后,将改由<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>向您提供日后的更新。"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"此应用的更新目前由<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>管理。\n\n要安装这个来自<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>的更新吗?"</string>
<string name="install_failed" msgid="5777824004474125469">"未安装应用。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系统已禁止安装该软件包。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"应用未安装:软件包与现有软件包存在冲突。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 0ed0bd7..d7fb07e 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝此應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此應用程式嗎?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"此應用程式的更新目前由「<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>」管理。\n\n更新後將改由「<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>」提供更新。"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"此應用程式的更新目前由「<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>」管理。\n\n是否要安裝這項由「<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>」提供的更新?"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"套件已遭封鎖,無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"套件與現有的套件發生衝突,無法安裝應用程式。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index 9dfb3fd..a825d20 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝這個應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新這個應用程式嗎?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"這個應用程式的更新目前是由「<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>」管理。\n\n更新後,將改由「<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>」提供更新。"</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"這個應用程式的更新目前是由「<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>」管理。\n\n是否要安裝「<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>」提供的這項更新?"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系統已封鎖這個套件,因此無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"應用程式套件與現有套件衝突,因此未能完成安裝。"</string>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index f5e6b75..62c8a9a 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -26,10 +26,8 @@
<string name="install_done" msgid="5987363587661783896">"Uhlelo lokusebenza olufakiwe."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingabe ufuna ukufaka le app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingabe ufuna ukubuyekeza le app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_changed (4215696609006069124) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (8778026710268011466) -->
- <skip />
+ <string name="install_confirm_question_update_owner_changed" msgid="4215696609006069124">"Izibuyekezo zale app okwamanje ziphethwe yi-<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nNgokubuyekeza, kunalokho uzothola izibuyekezo zesikhathi esizayo ezivela ku-<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g> esikhundleni."</string>
+ <string name="install_confirm_question_update_owner_reminder" msgid="8778026710268011466">"Izibuyekezo zale app okwamanje ziphethwe yi-<xliff:g id="EXISTING_UPDATE_OWNER">%1$s</xliff:g>.\n\nUyafuna ukufaka lesi sibuyekezo esivela ku-<xliff:g id="NEW_UPDATE_OWNER">%2$s</xliff:g>."</string>
<string name="install_failed" msgid="5777824004474125469">"Uhlelo lokusebenza alufakiwe."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Iphakheji livinjiwe kusukela ekufakweni."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Uhlelo lokusebenza alufakiwe njengoba ukuphakheja kushayisana nephakheji elikhona."</string>
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index cb2baa9..ae6f71c 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -143,6 +143,8 @@
<!-- [CHAR LIMIT=100] -->
<string name="uninstall_done_app">Uninstalled <xliff:g id="package_label">%1$s</xliff:g></string>
<!-- [CHAR LIMIT=100] -->
+ <string name="uninstall_done_clone_app">Deleted <xliff:g id="package_label">%1$s</xliff:g> clone</string>
+ <!-- [CHAR LIMIT=100] -->
<string name="uninstall_failed">Uninstall unsuccessful.</string>
<!-- [CHAR LIMIT=100] -->
<string name="uninstall_failed_app">Uninstalling <xliff:g id="package_label">%1$s</xliff:g> unsuccessful.</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
index b9552fc..e089aef 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
@@ -49,6 +49,7 @@
static final String EXTRA_UNINSTALL_ID = "com.android.packageinstaller.extra.UNINSTALL_ID";
static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
+ static final String EXTRA_IS_CLONE_APP = "com.android.packageinstaller.extra.IS_CLONE_APP";
@Override
public void onReceive(Context context, Intent intent) {
@@ -84,7 +85,10 @@
case PackageInstaller.STATUS_SUCCESS:
notificationManager.cancel(uninstallId);
- Toast.makeText(context, context.getString(R.string.uninstall_done_app, appLabel),
+ boolean isCloneApp = intent.getBooleanExtra(EXTRA_IS_CLONE_APP, false);
+ Toast.makeText(context, isCloneApp
+ ? context.getString(R.string.uninstall_done_clone_app, appLabel)
+ : context.getString(R.string.uninstall_done_app, appLabel),
Toast.LENGTH_LONG).show();
return;
case PackageInstaller.STATUS_FAILURE_BLOCKED: {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index 04496b9..7250bdd 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -67,6 +67,7 @@
private static final String TAG = "UninstallerActivity";
private static final String UNINSTALLING_CHANNEL = "uninstalling";
+ private boolean mIsClonedApp;
public static class DialogInfo {
public ApplicationInfo appInfo;
@@ -277,6 +278,14 @@
fragment.show(ft, "dialog");
}
+ /**
+ * Starts uninstall of app.
+ */
+ public void startUninstallProgress(boolean keepData, boolean isClonedApp) {
+ mIsClonedApp = isClonedApp;
+ startUninstallProgress(keepData);
+ }
+
public void startUninstallProgress(boolean keepData) {
boolean returnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
CharSequence label = mDialogInfo.appInfo.loadSafeLabel(getPackageManager());
@@ -329,6 +338,7 @@
broadcastIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo);
broadcastIntent.putExtra(UninstallFinish.EXTRA_APP_LABEL, label);
broadcastIntent.putExtra(UninstallFinish.EXTRA_UNINSTALL_ID, uninstallId);
+ broadcastIntent.putExtra(UninstallFinish.EXTRA_IS_CLONE_APP, mIsClonedApp);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(this, uninstallId, broadcastIntent,
@@ -343,7 +353,10 @@
Notification uninstallingNotification =
(new Notification.Builder(this, UNINSTALLING_CHANNEL))
.setSmallIcon(R.drawable.ic_remove).setProgress(0, 1, true)
- .setContentTitle(getString(R.string.uninstalling_app, label)).setOngoing(true)
+ .setContentTitle(mIsClonedApp
+ ? getString(R.string.uninstalling_cloned_app, label)
+ : getString(R.string.uninstalling_app, label))
+ .setOngoing(true)
.build();
notificationManager.notify(uninstallId, uninstallingNotification);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index 1bbdad5..4a93bf8 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -54,6 +54,7 @@
private static final String LOG_TAG = UninstallAlertDialogFragment.class.getSimpleName();
private @Nullable CheckBox mKeepData;
+ private boolean mIsClonedApp;
/**
* Get number of bytes of the app data of the package.
@@ -125,7 +126,6 @@
messageBuilder.append(" ").append(appLabel).append(".\n\n");
}
}
- boolean isClonedApp = false;
final boolean isUpdate =
((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
@@ -154,7 +154,7 @@
userName));
} else if (customUserManager.isUserOfType(USER_TYPE_PROFILE_CLONE)
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
- isClonedApp = true;
+ mIsClonedApp = true;
messageBuilder.append(getString(
R.string.uninstall_application_text_current_user_clone_profile));
} else {
@@ -162,7 +162,7 @@
getString(R.string.uninstall_application_text_user, userName));
}
} else if (isCloneProfile(myUserHandle)) {
- isClonedApp = true;
+ mIsClonedApp = true;
messageBuilder.append(getString(
R.string.uninstall_application_text_current_user_clone_profile));
} else {
@@ -177,7 +177,7 @@
}
}
- if (isClonedApp) {
+ if (mIsClonedApp) {
dialogBuilder.setTitle(getString(R.string.cloned_app_label, appLabel));
} else {
dialogBuilder.setTitle(appLabel);
@@ -236,7 +236,7 @@
UserManager userManager = getContext().getSystemService(UserManager.class);
List<UserHandle> profiles = userManager.getUserProfiles();
for (UserHandle userHandle : profiles) {
- if (!Process.myUserHandle().equals(UserHandle.SYSTEM) && isCloneProfile(userHandle)) {
+ if (!userHandle.equals(UserHandle.SYSTEM) && isCloneProfile(userHandle)) {
cloneUser = userHandle;
break;
}
@@ -260,7 +260,7 @@
public void onClick(DialogInterface dialog, int which) {
if (which == Dialog.BUTTON_POSITIVE) {
((UninstallerActivity) getActivity()).startUninstallProgress(
- mKeepData != null && mKeepData.isChecked());
+ mKeepData != null && mKeepData.isChecked(), mIsClonedApp);
} else {
((UninstallerActivity) getActivity()).dispatchAborted();
}
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml
index b5a70d0..595e46d 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Toegelaat"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nie toegelaat nie"</string>
<string name="version_text" msgid="4001669804596458577">"weergawe <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml
index 3cc6e89..e2a1bf5 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ይፈቀዳል"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"አይፈቀድም"</string>
<string name="version_text" msgid="4001669804596458577">"ሥሪት <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"የተባዛ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml
index 2e0a9ef..9a8e7dd 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"مسموح به"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غير مسموح به"</string>
<string name="version_text" msgid="4001669804596458577">"الإصدار <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"نسخة طبق الأصل من \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\""</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml
index dd27aa1..2e8140e 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"অনুমতি দিয়া হৈছে"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"অনুমতি নাই"</string>
<string name="version_text" msgid="4001669804596458577">"সংস্কৰণ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ৰ ক্ল’ন"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml
index 1fc9c36..c6518c8 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"İcazə verildi"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"İcazə verilməyib"</string>
<string name="version_text" msgid="4001669804596458577">"versiya <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kopyalanması"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml
index 3d5caaf..f874c6d 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozvoljeno"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dozvoljeno"</string>
<string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon aplikacije <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml
index f3c3dd0..e3d3926 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дазволена"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Забаронена"</string>
<string name="version_text" msgid="4001669804596458577">"версія <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Клон \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\""</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml
index c16bea8..0f51436 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Разрешено"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Не е разрешено"</string>
<string name="version_text" msgid="4001669804596458577">"версия <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Копие на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml
index a72570f..71b3239 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"অনুমোদিত"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"অননুমোদিত"</string>
<string name="version_text" msgid="4001669804596458577">"ভার্সন <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ক্লোন"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml
index 9b98057..35983f6 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozvoljeno"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dozvoljeno"</string>
<string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Kloniranje paketa <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml
index 111abe3..70604be 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Amb permís"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Sense permís"</string>
<string name="version_text" msgid="4001669804596458577">"versió <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml
index f58e9c4..5a3e043 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Povoleno"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepovoleno"</string>
<string name="version_text" msgid="4001669804596458577">"verze <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon balíčku <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml
index 32ae008..c53441c 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tilladt"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ikke tilladt"</string>
<string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml
index 401d8c9..b10f020 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Zulässig"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nicht zulässig"</string>
<string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-Klon"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml
index ad751f5..ac4106a 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Επιτρέπεται"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Δεν επιτρέπεται"</string>
<string name="version_text" msgid="4001669804596458577">"έκδοση <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Κλώνος <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml
index b151c95..a0772f8 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
<string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml
index b151c95..a0772f8 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
<string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml
index b151c95..a0772f8 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
<string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml
index b08a73f..08da5f8 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"No se permite"</string>
<string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml
index 45da42c..32ba2f9 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"No permitida"</string>
<string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml
index d8f43d8..a216abc 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Lubatud"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Pole lubatud"</string>
<string name="version_text" msgid="4001669804596458577">"versioon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Üksuse <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kloon"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml
index 6505096..798cf35 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Baimena dauka"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ez dauka baimenik"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> bertsioa"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> aplikazioaren klona"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml
index 616cf87..8654c64 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"مجاز"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غیرمجاز"</string>
<string name="version_text" msgid="4001669804596458577">"نسخه <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"همتای <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml
index 161f2ae..8f42d50 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Sallittu"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ei sallittu"</string>
<string name="version_text" msgid="4001669804596458577">"versio <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klooni"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
index 5fd70cc..a271ff5 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Autorisé"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non autorisée"</string>
<string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml
index 239a86a..30f2bcd 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Autorisé"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non autorisé"</string>
<string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml
index 809d24d..a98e809 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non permitida"</string>
<string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml
index a1de2fb..7bff012 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"મંજૂરી છે"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"મંજૂરી નથી"</string>
<string name="version_text" msgid="4001669804596458577">"વર્ઝન <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ની ક્લોન"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml
index 9af4a02..1a962f5 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमति है"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमति नहीं है"</string>
<string name="version_text" msgid="4001669804596458577">"वर्शन <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> का क्लोन"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml
index 8556cfb..d179415 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dopušteno"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dopušteno"</string>
<string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml
index 9d928e9..4ccc59f 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Engedélyezve"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nem engedélyezett"</string>
<string name="version_text" msgid="4001669804596458577">"verzió: <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klónja"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml
index 064d9998..67b3e73 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Թույլատրված է"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Արգելված է"</string>
<string name="version_text" msgid="4001669804596458577">"տարբերակ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"«<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>» հավելվածի կլոն"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml
index 8799c9b..a2a4289c 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Diizinkan"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tidak diizinkan"</string>
<string name="version_text" msgid="4001669804596458577">"versi <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml
index ff7ee6a..5c21bec 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Leyft"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ekki leyft"</string>
<string name="version_text" msgid="4001669804596458577">"útgáfa <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Afrit af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml
index 5d67307..c8cbe76 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Consentita"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non consentita"</string>
<string name="version_text" msgid="4001669804596458577">"versione <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone di <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml
index 4ab76fe..49b6b1f 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"יש הרשאה"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"אין הרשאה"</string>
<string name="version_text" msgid="4001669804596458577">"גרסה <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"שכפול של <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml
index 1c0d8d3..2f15ab4 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"許可"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"許可しない"</string>
<string name="version_text" msgid="4001669804596458577">"バージョン <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> のクローン"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml
index a4c6783..502fcb1 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"დაშვებულია"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"დაუშვებელია"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> ვერსია"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> კლონი"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml
index 4760d47..1b5e8ed 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Рұқсат етілген"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Рұқсат етілмеген"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> нұсқасы"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клоны"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml
index 962fb5c..2eeb5ce 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"បានអនុញ្ញាត"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"មិនអនុញ្ញាតទេ"</string>
<string name="version_text" msgid="4001669804596458577">"កំណែ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"ក្លូន <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml
index 7edec75..04e7396 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ಅನುಮತಿಸಲಾಗಿದೆ"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string>
<string name="version_text" msgid="4001669804596458577">"ಆವೃತ್ತಿ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಕ್ಲೋನ್"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml
index 446580b..ef4ee0d 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"허용됨"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"허용되지 않음"</string>
<string name="version_text" msgid="4001669804596458577">"버전 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 클론"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml
index 2596b93..26fe636 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Уруксат берилген"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Тыюу салынган"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> версиясы"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клону"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml
index 0dc64a6..e707c9d 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ອະນຸຍາດແລ້ວ"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ບໍ່ໄດ້ອະນຸຍາດ"</string>
<string name="version_text" msgid="4001669804596458577">"ເວີຊັນ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"ໂຄລນ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml
index 4ca01dc..8bcee5f 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Leidžiama"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Neleidžiama"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> versija"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"„<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>“ kopija"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml
index bf300ac..6d5017c 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Atļauja piešķirta"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Atļauja nav piešķirta"</string>
<string name="version_text" msgid="4001669804596458577">"versija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Lietotnes <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klons"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml
index 839e4c7..56ed2d9 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Со дозволен пристап"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Без дозволен пристап"</string>
<string name="version_text" msgid="4001669804596458577">"верзија <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Клон на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml
index 0aad964..1090690 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"അനുവാദം ലഭിച്ചു"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"അനുവാദം ലഭിച്ചില്ല"</string>
<string name="version_text" msgid="4001669804596458577">"പതിപ്പ് <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ക്ലോൺ ചെയ്യൽ"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml
index bc6e9ae..2074222 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Зөвшөөрсөн"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Зөвшөөрөөгүй"</string>
<string name="version_text" msgid="4001669804596458577">"хувилбар <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клон"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml
index 142a60f..36ee416 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमती असलेले"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमती नाही"</string>
<string name="version_text" msgid="4001669804596458577">"आवृत्ती <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोन"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml
index 0d39435..c2f3243 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dibenarkan"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tidak dibenarkan"</string>
<string name="version_text" msgid="4001669804596458577">"versi <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml
index f87608f..2d08eec 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ခွင့်ပြုထားသည်"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ခွင့်ပြုမထားပါ"</string>
<string name="version_text" msgid="4001669804596458577">"ဗားရှင်း <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ပုံတူပွား"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml
index 745834d..be739a2 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tillatt"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ikke tillatt"</string>
<string name="version_text" msgid="4001669804596458577">"versjon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon av <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml
index 4b99bae1..7f3a523 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमति दिइएका एप"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमति नदिइएका एप"</string>
<string name="version_text" msgid="4001669804596458577">"संस्करण <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोन"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml
index 9a6b767..4ea7fed 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Toegestaan"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Niet toegestaan"</string>
<string name="version_text" msgid="4001669804596458577">"versie <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Kloon van <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml
index e562d55..501dc5c 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ଅନୁମତି ଦିଆଯାଇନାହିଁ"</string>
<string name="version_text" msgid="4001669804596458577">"ଭର୍ସନ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> କ୍ଲୋନ"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml
index a24ec90..28fcf0b 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ਆਗਿਆ ਹੈ"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
<string name="version_text" msgid="4001669804596458577">"ਵਰਜਨ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ਦਾ ਕਲੋਨ"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml
index 7da29a5..c947a66 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozwolone"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Niedozwolone"</string>
<string name="version_text" msgid="4001669804596458577">"wersja <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klonuj: <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml
index 85a42e2..ba92ebb6 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitido"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitido"</string>
<string name="version_text" msgid="4001669804596458577">"Versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml
index 9db985d..e7030df 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitida"</string>
<string name="version_text" msgid="4001669804596458577">"versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml
index 85a42e2..ba92ebb6 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitido"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitido"</string>
<string name="version_text" msgid="4001669804596458577">"Versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml
index e808e4a..c78e9be 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permisă"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepermisă"</string>
<string name="version_text" msgid="4001669804596458577">"versiunea <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clonă pentru <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml
index 404ed31..3507bc7 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Разрешено"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Запрещено"</string>
<string name="version_text" msgid="4001669804596458577">"версия <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Клон приложения \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\""</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml
index 276cbc4..6014e07 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"ඉඩ දුන්"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ඉඩ නොදෙන"</string>
<string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> අනුවාදය"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ක්ලෝනය"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml
index d8dde40..9888125 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Povolené"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepovolené"</string>
<string name="version_text" msgid="4001669804596458577">"verzia <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml
index 4cb2a40..74b3ffd 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dovoljeno"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ni dovoljeno"</string>
<string name="version_text" msgid="4001669804596458577">"različica <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klonirani paket <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml
index ba3d3cb..37aa7f0 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Lejohet"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nuk lejohet"</string>
<string name="version_text" msgid="4001669804596458577">"versioni <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon i <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml
index 75caa5a..fe9b323 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дозвољено"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Није дозвољено"</string>
<string name="version_text" msgid="4001669804596458577">"верзија <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Клон апликације <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml
index e11bb12..189c26e 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tillåts"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tillåts inte"</string>
<string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Klon av <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml
index be04d8e..241376b 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Inaruhusiwa"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Hairuhusiwi"</string>
<string name="version_text" msgid="4001669804596458577">"toleo la <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Nakala ya <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml
index cab94e2..b8e5d3a 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"அனுமதிக்கப்பட்டது"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"அனுமதிக்கப்படவில்லை"</string>
<string name="version_text" msgid="4001669804596458577">"பதிப்பு <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> குளோன்"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml
index 721e86a..db41032 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"అనుమతించబడినవి"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"అనుమతించబడలేదు"</string>
<string name="version_text" msgid="4001669804596458577">"వెర్షన్ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> క్లోన్"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml
index 0844e24..ac38443 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"อนุญาต"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ไม่อนุญาต"</string>
<string name="version_text" msgid="4001669804596458577">"เวอร์ชัน <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"โคลนของ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml
index 1d0bead..065834b 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Pinapahintulutan"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Hindi pinapahintulutan"</string>
<string name="version_text" msgid="4001669804596458577">"bersyon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Clone ng <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml
index e3fcf4d..188a096 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"İzin veriliyor"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"İzin verilmiyor"</string>
<string name="version_text" msgid="4001669804596458577">"sürüm: <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klonu"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml
index 392738c..0a5ca4f 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дозволено"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Заборонено"</string>
<string name="version_text" msgid="4001669804596458577">"версія <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Копія додатка <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml
index c05c387..6b344fc 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"اجازت ہے"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"اجازت نہیں ہے"</string>
<string name="version_text" msgid="4001669804596458577">"ورژن <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> کلون"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml
index dbef24b..d5cf2b2 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Được phép"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Không được phép"</string>
<string name="version_text" msgid="4001669804596458577">"phiên bản <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"Bản sao của <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml
index fbd6fc7..fd16dea 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"已允许"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允许"</string>
<string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>克隆"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml
index c05e560..98071b9 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"允許"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允許"</string>
<string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」複製本"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml
index c05e560..03efe37 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"允許"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允許"</string>
<string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」副本"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml
index 45d11cc..088bb0f 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml
@@ -23,6 +23,5 @@
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Kuvumelekile"</string>
<string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Akuvumelekile"</string>
<string name="version_text" msgid="4001669804596458577">"Uhlobo <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
- <!-- no translation found for cloned_app_info_label (1765651167024478391) -->
- <skip />
+ <string name="cloned_app_info_label" msgid="1765651167024478391">"I-<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ye-clone"</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
index a2fb101..3b9bf47 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
@@ -33,7 +33,6 @@
fun DisposableBroadcastReceiverAsUser(
intentFilter: IntentFilter,
userHandle: UserHandle,
- onStart: () -> Unit = {},
onReceive: (Intent) -> Unit,
) {
val context = LocalContext.current
@@ -49,7 +48,6 @@
context.registerReceiverAsUser(
broadcastReceiver, userHandle, intentFilter, null, null
)
- onStart()
},
onStop = {
context.unregisterReceiver(broadcastReceiver)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index ce0c551..5342def 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -29,19 +29,11 @@
import kotlinx.coroutines.runBlocking
/**
- * The config used to load the App List.
- */
-data class AppListConfig(
- val userId: Int,
- val showInstantApps: Boolean,
-)
-
-/**
* The repository to load the App List data.
*/
internal interface AppListRepository {
/** Loads the list of [ApplicationInfo]. */
- suspend fun loadApps(config: AppListConfig): List<ApplicationInfo>
+ suspend fun loadApps(userId: Int, showInstantApps: Boolean): List<ApplicationInfo>
/** Gets the flow of predicate that could used to filter system app. */
fun showSystemPredicate(
@@ -50,7 +42,7 @@
): Flow<(app: ApplicationInfo) -> Boolean>
/** Gets the system app package names. */
- fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String>
+ fun getSystemPackageNamesBlocking(userId: Int, showInstantApps: Boolean): Set<String>
}
/**
@@ -59,15 +51,21 @@
object AppListRepositoryUtil {
/** Gets the system app package names. */
@JvmStatic
- fun getSystemPackageNames(context: Context, config: AppListConfig): Set<String> {
- return AppListRepositoryImpl(context).getSystemPackageNamesBlocking(config)
- }
+ fun getSystemPackageNames(
+ context: Context,
+ userId: Int,
+ showInstantApps: Boolean,
+ ): Set<String> =
+ AppListRepositoryImpl(context).getSystemPackageNamesBlocking(userId, showInstantApps)
}
internal class AppListRepositoryImpl(private val context: Context) : AppListRepository {
private val packageManager = context.packageManager
- override suspend fun loadApps(config: AppListConfig): List<ApplicationInfo> = coroutineScope {
+ override suspend fun loadApps(
+ userId: Int,
+ showInstantApps: Boolean,
+ ): List<ApplicationInfo> = coroutineScope {
val hiddenSystemModulesDeferred = async {
packageManager.getInstalledModules(0)
.filter { it.isHidden }
@@ -82,12 +80,12 @@
PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong()
)
val installedApplicationsAsUser =
- packageManager.getInstalledApplicationsAsUser(flags, config.userId)
+ packageManager.getInstalledApplicationsAsUser(flags, userId)
val hiddenSystemModules = hiddenSystemModulesDeferred.await()
val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
installedApplicationsAsUser.filter { app ->
- app.isInAppList(config.showInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+ app.isInAppList(showInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
}
}
@@ -97,18 +95,17 @@
): Flow<(app: ApplicationInfo) -> Boolean> =
userIdFlow.combine(showSystemFlow, ::showSystemPredicate)
- override fun getSystemPackageNamesBlocking(config: AppListConfig) = runBlocking {
- getSystemPackageNames(config)
- }
+ override fun getSystemPackageNamesBlocking(userId: Int, showInstantApps: Boolean) =
+ runBlocking { getSystemPackageNames(userId, showInstantApps) }
- private suspend fun getSystemPackageNames(config: AppListConfig): Set<String> =
- coroutineScope {
- val loadAppsDeferred = async { loadApps(config) }
- val homeOrLauncherPackages = loadHomeOrLauncherPackages(config.userId)
- val showSystemPredicate =
- { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) }
- loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet()
- }
+ private suspend fun getSystemPackageNames(userId: Int, showInstantApps: Boolean): Set<String> =
+ coroutineScope {
+ val loadAppsDeferred = async { loadApps(userId, showInstantApps) }
+ val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId)
+ val showSystemPredicate =
+ { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) }
+ loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet()
+ }
private suspend fun showSystemPredicate(
userId: Int,
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt
index 6cd1c0d..8896042 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt
@@ -26,6 +26,7 @@
import com.android.settingslib.spa.framework.util.asyncMapItem
import com.android.settingslib.spa.framework.util.waitFirst
import com.android.settingslib.spa.widget.ui.SpinnerOption
+import com.android.settingslib.spaprivileged.template.app.AppListConfig
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -34,8 +35,8 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
@@ -78,32 +79,77 @@
private val labelMap = ConcurrentHashMap<String, String>()
private val scope = viewModelScope + Dispatchers.IO
- private val userIdFlow = appListConfig.flow.map { it.userId }
+ private val userSubGraphsFlow = appListConfig.flow.map { config ->
+ config.userIds.map { userId -> UserSubGraph(userId, config.showInstantApps) }
+ }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
- private val appsStateFlow = MutableStateFlow<List<ApplicationInfo>?>(null)
+ private inner class UserSubGraph(
+ private val userId: Int,
+ private val showInstantApps: Boolean,
+ ) {
+ private val userIdFlow = flowOf(userId)
- private val recordListFlow = listModel.flow
- .flatMapLatest { it.transform(userIdFlow, appsStateFlow.filterNotNull()) }
- .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
+ private val appsStateFlow = MutableStateFlow<List<ApplicationInfo>?>(null)
- private val systemFilteredFlow =
- appListRepository.showSystemPredicate(userIdFlow, showSystem.flow)
- .combine(recordListFlow) { showAppPredicate, recordList ->
- recordList.filter { showAppPredicate(it.app) }
+ val recordListFlow = listModel.flow
+ .flatMapLatest { it.transform(userIdFlow, appsStateFlow.filterNotNull()) }
+ .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
+
+ private val systemFilteredFlow =
+ appListRepository.showSystemPredicate(userIdFlow, showSystem.flow)
+ .combine(recordListFlow) { showAppPredicate, recordList ->
+ recordList.filter { showAppPredicate(it.app) }
+ }
+ .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
+
+ val listModelFilteredFlow = optionFlow.filterNotNull().flatMapLatest { option ->
+ listModel.flow.flatMapLatest { listModel ->
+ listModel.filter(this.userIdFlow, option, this.systemFilteredFlow)
}
+ }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
+
+ fun reloadApps() {
+ scope.launch {
+ appsStateFlow.value = appListRepository.loadApps(userId, showInstantApps)
+ }
+ }
+ }
+
+ private val combinedRecordListFlow = userSubGraphsFlow.flatMapLatest { userSubGraphList ->
+ combine(userSubGraphList.map { it.recordListFlow }) { it.toList().flatten() }
+ }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
override val spinnerOptionsFlow =
- recordListFlow.combine(listModel.flow) { recordList, listModel ->
+ combinedRecordListFlow.combine(listModel.flow) { recordList, listModel ->
listModel.getSpinnerOptions(recordList)
- }
+ }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
- override val appListDataFlow = optionFlow.filterNotNull().flatMapLatest(::filterAndSort)
- .combine(searchQuery.flow) { appListData, searchQuery ->
+ private val appEntryListFlow = userSubGraphsFlow.flatMapLatest { userSubGraphList ->
+ combine(userSubGraphList.map { it.listModelFilteredFlow }) { it.toList().flatten() }
+ }.asyncMapItem { record ->
+ val label = getLabel(record.app)
+ AppEntry(
+ record = record,
+ label = label,
+ labelCollationKey = collator.getCollationKey(label),
+ )
+ }
+
+ override val appListDataFlow =
+ combine(
+ appEntryListFlow,
+ listModel.flow,
+ optionFlow.filterNotNull(),
+ ) { appEntries, listModel, option ->
+ AppListData(
+ appEntries = appEntries.sortedWith(listModel.getComparator(option)),
+ option = option,
+ )
+ }.combine(searchQuery.flow) { appListData, searchQuery ->
appListData.filter {
it.label.contains(other = searchQuery, ignoreCase = true)
}
- }
- .shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
+ }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1)
init {
scheduleOnFirstLoaded()
@@ -111,30 +157,16 @@
fun reloadApps() {
scope.launch {
- appsStateFlow.value = appListRepository.loadApps(appListConfig.flow.first())
+ userSubGraphsFlow.collect { userSubGraphList ->
+ for (userSubGraph in userSubGraphList) {
+ userSubGraph.reloadApps()
+ }
+ }
}
}
- private fun filterAndSort(option: Int) = listModel.flow.flatMapLatest { listModel ->
- listModel.filter(userIdFlow, option, systemFilteredFlow)
- .asyncMapItem { record ->
- val label = getLabel(record.app)
- AppEntry(
- record = record,
- label = label,
- labelCollationKey = collator.getCollationKey(label),
- )
- }
- .map { appEntries ->
- AppListData(
- appEntries = appEntries.sortedWith(listModel.getComparator(option)),
- option = option,
- )
- }
- }
-
private fun scheduleOnFirstLoaded() {
- recordListFlow
+ combinedRecordListFlow
.waitFirst(appListDataFlow)
.combine(listModel.flow) { recordList, listModel ->
if (listModel.onFirstLoaded(recordList)) {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index 57a60e5..4a8c00e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -32,6 +32,7 @@
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.settingslib.spa.framework.compose.LifecycleEffect
import com.android.settingslib.spa.framework.compose.LogCompositions
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
@@ -43,7 +44,6 @@
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
import com.android.settingslib.spaprivileged.model.app.AppEntry
-import com.android.settingslib.spaprivileged.model.app.AppListConfig
import com.android.settingslib.spaprivileged.model.app.AppListData
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppListViewModel
@@ -56,6 +56,14 @@
private const val TAG = "AppList"
private const val CONTENT_TYPE_HEADER = "header"
+/**
+ * The config used to load the App List.
+ */
+data class AppListConfig(
+ val userIds: List<Int>,
+ val showInstantApps: Boolean,
+)
+
data class AppListState(
val showSystem: State<Boolean>,
val searchQuery: State<String>,
@@ -84,7 +92,7 @@
internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
viewModelSupplier: @Composable () -> IAppListViewModel<T>,
) {
- LogCompositions(TAG, config.userId.toString())
+ LogCompositions(TAG, config.userIds.toString())
val viewModel = viewModelSupplier()
Column(Modifier.fillMaxSize()) {
val optionsState = viewModel.spinnerOptionsFlow.collectAsState(null, Dispatchers.IO)
@@ -168,21 +176,23 @@
listModel: AppListModel<T>,
state: AppListState,
): AppListViewModel<T> {
- val viewModel: AppListViewModel<T> = viewModel(key = config.userId.toString())
+ val viewModel: AppListViewModel<T> = viewModel(key = config.userIds.toString())
viewModel.appListConfig.setIfAbsent(config)
viewModel.listModel.setIfAbsent(listModel)
viewModel.showSystem.Sync(state.showSystem)
viewModel.searchQuery.Sync(state.searchQuery)
- DisposableBroadcastReceiverAsUser(
- intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_CHANGED)
- addDataScheme("package")
- },
- userHandle = UserHandle.of(config.userId),
- onStart = { viewModel.reloadApps() },
- ) { viewModel.reloadApps() }
-
+ LifecycleEffect(onStart = { viewModel.reloadApps() })
+ val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
+ addDataScheme("package")
+ }
+ for (userId in config.userIds) {
+ DisposableBroadcastReceiverAsUser(
+ intentFilter = intentFilter,
+ userHandle = UserHandle.of(userId),
+ ) { viewModel.reloadApps() }
+ }
return viewModel
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 404e27c..2ebbe8a 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -24,10 +24,9 @@
import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
import com.android.settingslib.spa.widget.scaffold.SearchScaffold
import com.android.settingslib.spaprivileged.R
-import com.android.settingslib.spaprivileged.model.app.AppListConfig
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
-import com.android.settingslib.spaprivileged.template.common.WorkProfilePager
+import com.android.settingslib.spaprivileged.template.common.UserProfilePager
/**
* The full screen template for an App List page.
@@ -55,10 +54,10 @@
}
},
) { bottomPadding, searchQuery ->
- WorkProfilePager(primaryUserOnly) { userInfo ->
+ UserProfilePager(primaryUserOnly) { userGroup ->
val appListInput = AppListInput(
config = AppListConfig(
- userId = userInfo.id,
+ userIds = userGroup.userInfos.map { it.id },
showInstantApps = showInstantApps,
),
listModel = listModel,
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
new file mode 100644
index 0000000..b5a4929
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.common
+
+import android.content.pm.UserInfo
+import android.content.pm.UserProperties
+import android.os.UserHandle
+import android.os.UserManager
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
+import com.android.settingslib.spa.widget.scaffold.SettingsPager
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository
+
+/**
+ * Info about how to group multiple profiles for Settings.
+ *
+ * @see [UserProperties.ShowInSettings]
+ */
+data class UserGroup(
+ /** The users in this user group, if multiple users, the first one is parent user. */
+ val userInfos: List<UserInfo>,
+)
+
+@Composable
+fun UserProfilePager(
+ primaryUserOnly: Boolean = false,
+ content: @Composable (userGroup: UserGroup) -> Unit,
+) {
+ val context = LocalContext.current
+ val userGroups = remember {
+ context.userManager.getUserGroups(primaryUserOnly)
+ }
+ val titles = remember {
+ val enterpriseRepository = EnterpriseRepository(context)
+ userGroups.map { userGroup ->
+ enterpriseRepository.getProfileTitle(
+ isManagedProfile = userGroup.userInfos.first().isManagedProfile,
+ )
+ }
+ }
+
+ SettingsPager(titles) { page ->
+ content(userGroups[page])
+ }
+}
+
+private fun UserManager.getUserGroups(primaryUserOnly: Boolean): List<UserGroup> {
+ val userGroupList = mutableListOf<UserGroup>()
+ val profileToShowInSettingsList = getProfiles(UserHandle.myUserId())
+ .filter { userInfo -> !primaryUserOnly || userInfo.isPrimary }
+ .map { userInfo -> userInfo to getUserProperties(userInfo.userHandle).showInSettings }
+
+ profileToShowInSettingsList.filter { it.second == UserProperties.SHOW_IN_SETTINGS_WITH_PARENT }
+ .takeIf { it.isNotEmpty() }
+ ?.map { it.first }
+ ?.let { userInfos -> userGroupList += UserGroup(userInfos) }
+
+ profileToShowInSettingsList.filter { it.second == UserProperties.SHOW_IN_LAUNCHER_SEPARATE }
+ .forEach { userGroupList += UserGroup(userInfos = listOf(it.first)) }
+
+ return userGroupList
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt
deleted file mode 100644
index a76c438..0000000
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spaprivileged.template.common
-
-import android.content.pm.UserInfo
-import android.os.UserHandle
-import android.os.UserManager
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalContext
-import com.android.settingslib.spa.widget.scaffold.SettingsPager
-import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository
-
-@Composable
-fun WorkProfilePager(
- primaryUserOnly: Boolean = false,
- content: @Composable (userInfo: UserInfo) -> Unit,
-) {
- val context = LocalContext.current
- val profiles = remember {
- val userManager = checkNotNull(context.getSystemService(UserManager::class.java))
- userManager.getProfiles(UserHandle.myUserId()).filter { userInfo ->
- !primaryUserOnly || userInfo.isPrimary
- }
- }
- val titles = remember {
- val enterpriseRepository = EnterpriseRepository(context)
- profiles.map {
- enterpriseRepository.getProfileTitle(isManagedProfile = it.isManagedProfile)
- }
- }
-
- SettingsPager(titles) { page ->
- content(profiles[page])
- }
-}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
index 01f4cc6..9bd9242 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
@@ -85,23 +85,6 @@
assertThat(onReceiveIsCalled).isTrue()
}
- @Test
- fun broadcastReceiver_onStartIsCalled() {
- var onStartIsCalled = false
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- DisposableBroadcastReceiverAsUser(
- intentFilter = IntentFilter(),
- userHandle = USER_HANDLE,
- onStart = { onStartIsCalled = true },
- onReceive = {},
- )
- }
- }
-
- assertThat(onStartIsCalled).isTrue()
- }
-
private companion object {
val USER_HANDLE: UserHandle = UserHandle.of(0)
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index b0ea40a..57972ed 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -83,9 +83,8 @@
@Test
fun loadApps_notShowInstantApps() = runTest {
mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).containsExactly(NORMAL_APP)
}
@@ -93,9 +92,8 @@
@Test
fun loadApps_showInstantApps() = runTest {
mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = true)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = true)
assertThat(appListFlow).containsExactly(NORMAL_APP, INSTANT_APP)
}
@@ -109,9 +107,8 @@
whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames))
.thenReturn(arrayOf(app.packageName))
mockInstalledApplications(listOf(app))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).isEmpty()
}
@@ -126,9 +123,8 @@
whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames))
.thenReturn(arrayOf(app.packageName))
mockInstalledApplications(listOf(app))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).isEmpty()
}
@@ -142,9 +138,8 @@
whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames))
.thenReturn(arrayOf(app.packageName))
mockInstalledApplications(listOf(app))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).containsExactly(app)
}
@@ -157,9 +152,8 @@
enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
}
mockInstalledApplications(listOf(app))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).containsExactly(app)
}
@@ -171,9 +165,8 @@
enabled = false
}
mockInstalledApplications(listOf(app))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
- val appListFlow = repository.loadApps(appListConfig)
+ val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false)
assertThat(appListFlow).isEmpty()
}
@@ -223,7 +216,7 @@
@Test
fun showSystemPredicate_appInLauncher() = runTest {
- val app = IN_LAUMCHER_APP
+ val app = IN_LAUNCHER_APP
whenever(
packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), eq(USER_ID))
@@ -237,10 +230,13 @@
@Test
fun getSystemPackageNames_returnExpectedValues() = runTest {
mockInstalledApplications(listOf(
- NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUMCHER_APP))
- val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
+ NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP))
- val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames(context, appListConfig)
+ val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames(
+ context = context,
+ userId = USER_ID,
+ showInstantApps = false,
+ )
assertThat(systemPackageNames).containsExactly("system.app", "home.app", "app.in.launcher")
}
@@ -280,7 +276,7 @@
flags = ApplicationInfo.FLAG_SYSTEM
}
- val IN_LAUMCHER_APP = ApplicationInfo().apply {
+ val IN_LAUNCHER_APP = ApplicationInfo().apply {
packageName = "app.in.launcher"
flags = ApplicationInfo.FLAG_SYSTEM
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
index b1d02f5..fc40aed 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
@@ -23,6 +23,7 @@
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.util.mapItem
import com.android.settingslib.spa.testutils.waitUntil
+import com.android.settingslib.spaprivileged.template.app.AppListConfig
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -84,14 +85,17 @@
}
private object FakeAppListRepository : AppListRepository {
- override suspend fun loadApps(config: AppListConfig) = listOf(APP)
+ override suspend fun loadApps(userId: Int, showInstantApps: Boolean) = listOf(APP)
override fun showSystemPredicate(
userIdFlow: Flow<Int>,
showSystemFlow: Flow<Boolean>,
): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true }
- override fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String> = setOf()
+ override fun getSystemPackageNamesBlocking(
+ userId: Int,
+ showInstantApps: Boolean,
+ ): Set<String> = emptySet()
}
private object FakeAppRepository : AppRepository {
@@ -105,7 +109,7 @@
const val USER_ID = 0
const val PACKAGE_NAME = "package.name"
const val LABEL = "Label"
- val CONFIG = AppListConfig(userId = USER_ID, showInstantApps = false)
+ val CONFIG = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false)
val APP = ApplicationInfo().apply {
packageName = PACKAGE_NAME
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
index d5c7c19..a99d02d 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
@@ -32,7 +32,6 @@
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppEntry
-import com.android.settingslib.spaprivileged.model.app.AppListConfig
import com.android.settingslib.spaprivileged.model.app.AppListData
import com.android.settingslib.spaprivileged.model.app.IAppListViewModel
import com.android.settingslib.spaprivileged.tests.testutils.TestAppListModel
@@ -115,7 +114,7 @@
) {
composeTestRule.setContent {
AppListInput(
- config = AppListConfig(userId = USER_ID, showInstantApps = false),
+ config = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false),
listModel = TestAppListModel(enableGrouping = enableGrouping),
state = AppListState(
showSystem = false.toState(),
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index a188fea..f9745e0 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -309,8 +309,8 @@
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"প্ৰতিটো লগ বাফাৰত ল\'গাৰৰ আকাৰ বাছনি কৰক"</string>
<string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"লগাৰৰ স্থায়ী ষ্ট’ৰেজৰ বস্তুবোৰ মচিবনে?"</string>
<string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"পাৰ্ছিছটেণ্ট লগাৰ ব্যৱহাৰ কৰ নিৰীক্ষণ নকৰাৰ সময়ত, আমি আপোনাৰ ডিভাইচত থকা লগাৰ ডেটা নিৱাসীক মচা দৰকাৰ।"</string>
- <string name="select_logpersist_title" msgid="447071974007104196">"ডিভাইচটোত লগাৰৰ ডেটা নিৰবচ্ছিন্নভাৱে সঞ্চয় কৰক"</string>
- <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"ডিভাইচত স্থায়ীভাৱে সঞ্চয় কৰিবলৈ লগ বাফাৰবোৰ বাছনি কৰক"</string>
+ <string name="select_logpersist_title" msgid="447071974007104196">"ডিভাইচটোত লগাৰৰ ডেটা নিৰবচ্ছিন্নভাৱে ষ্ট’ৰ কৰক"</string>
+ <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"ডিভাইচত স্থায়ীভাৱে ষ্ট’ৰ কৰিবলৈ লগ বাফাৰবোৰ বাছনি কৰক"</string>
<string name="select_usb_configuration_title" msgid="6339801314922294586">"ইউএছবি কনফিগাৰেশ্বন বাছনি কৰক"</string>
<string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"ইউএছবি কনফিগাৰেশ্বন বাছনি কৰক"</string>
<string name="allow_mock_location" msgid="2102650981552527884">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 80d90b7..2d01b37 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -173,7 +173,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Օգտատեր՝ <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Որոշ կանխադրված կարգավորումներ կան"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Կանխադրված կարգավորումներ չկան"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Տեքստի հնչեցման կարգավորումներ"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Տեքստի հնչեցման կարգավորումներ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Տեքստի հնչեցում"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Խոսքի արագությունը"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Տեքստի արտասանման արագությունը"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 23df3be..b2a8459 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -173,7 +173,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Колдонуучу: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Айрым демейки параметрлер туураланды"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Демейки маанилер коюлган жок"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Кеп синтезаторунун жөндөөлөрү"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Кеп синтезаторунун параметрлери"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Кеп синтезатору"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Кеп ылдамдыгы"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Текст айтылчу ылдамдык"</string>
@@ -219,9 +219,9 @@
<string name="development_settings_enable" msgid="4285094651288242183">"Иштеп чыгуучунун параметрлерин иштетүү"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Колдонмо өндүрүү мүмкүнчүлүктөрүн орнотуу"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Бул колдонуучуга өнүктүүрүүчү мүмкүнчүлүктөрү берилген эмес."</string>
- <string name="vpn_settings_not_available" msgid="2894137119965668920">"Бул колдонуучу VPN жөндөөлөрүн колдоно албайт"</string>
- <string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу модем режиминин жөндөөлөрүн өзгөртө албайт"</string>
- <string name="apn_settings_not_available" msgid="1147111671403342300">"Бул колдонуучу мүмкүндүк алуу түйүнүнүн аталышынын жөндөөлөрүн колдоно албайт"</string>
+ <string name="vpn_settings_not_available" msgid="2894137119965668920">"Бул колдонуучу VPN параметрлерин колдоно албайт"</string>
+ <string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу модем режиминин параметрлерин өзгөртө албайт"</string>
+ <string name="apn_settings_not_available" msgid="1147111671403342300">"Бул колдонуучу мүмкүндүк алуу түйүнүнүн аталышынын параметрлерин колдоно албайт"</string>
<string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB компьютерге сайылганда мүчүлүштүктөрдү оңдоо режими иштейт"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү аныктоо уруксатын артка кайтаруу"</string>
@@ -322,7 +322,7 @@
<string name="adb_warning_message" msgid="8145270656419669221">"USB-жөндөө - өндүрүү максатында гана түзүлгөн. Аны компүтериңиз менен түзмөгүңүздүн ортосунда берилиштерди алмашуу, түзмөгүңүзгө колдонмолорду эскертүүсүз орнотуу жана лог берилиштерин окуу үчүн колдонсоңуз болот."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат бересизби?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"Сиз мурун USB жөндөөлөрүнө уруксат берген бардык компүтерлердин жеткиси жокко чыгарылсынбы?"</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"Сиз мурун USB параметрлерине уруксат берген бардык компүтерлердин жеткиси жокко чыгарылсынбы?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Параметрлерди өзгөртүү"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Орнотулуучу колдонмону текшерүү"</string>
@@ -420,7 +420,7 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Күйгүзүү үчүн басып коюңуз."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Өчүрүү үчүн басып коюңуз."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Көшүү режиминдеги колдонмонун абалы:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <string name="transcode_settings_title" msgid="2581975870429850549">"Медиа файлдарды транскоддоо жөндөөлөрү"</string>
+ <string name="transcode_settings_title" msgid="2581975870429850549">"Медиа файлдарды транскоддоо параметрлери"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"Демейки жүргүзүлгөн транскоддоону өзгөртүп коюу"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Транскоддоо жүргүзүүнү иштетүү"</string>
<string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 166b3f0..c148eba 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -173,7 +173,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"အသုံးပြုသူ- <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"မူရင်းအချို့ သတ်မှတ်ပြီး"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"မူရင်း သတ်မှတ်မထားပါ။"</string>
- <string name="tts_settings" msgid="8130616705989351312">"စာ-မှ-စကားပြောင်းခြင်း ဆက်တင်များ"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"စာ-မှ-စကား ဆက်တင်များ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"စာ-မှ-စကားသို့ အထွက်"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"စကားပြောနှုန်း"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"စာတမ်းအားပြောဆိုသော အမြန်နှုန်း"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index db224be..a82f070 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -30,6 +30,8 @@
public static final String CATEGORY_APPS = "com.android.settings.category.ia.apps";
public static final String CATEGORY_APPS_DEFAULT =
"com.android.settings.category.ia.apps.default";
+ public static final String CATEGORY_SPECIAL_APP_ACCESS =
+ "com.android.settings.category.ia.special_app_access";
public static final String CATEGORY_BATTERY = "com.android.settings.category.ia.battery";
public static final String CATEGORY_DISPLAY = "com.android.settings.category.ia.display";
public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound";
diff --git a/packages/SettingsProvider/res/values-ky/strings.xml b/packages/SettingsProvider/res/values-ky/strings.xml
index 8058b4d..7ab6582 100644
--- a/packages/SettingsProvider/res/values-ky/strings.xml
+++ b/packages/SettingsProvider/res/values-ky/strings.xml
@@ -20,6 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"Жөндөөлөрдү сактоо"</string>
- <string name="wifi_softap_config_change" msgid="5688373762357941645">"Байланыш түйүнү жөндөөлөрү өзгөрдү"</string>
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"Байланыш түйүнү параметрлери өзгөрдү"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Чоо-жайын билүү үчүн басыңыз"</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ede69be..75d28d5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -228,9 +228,6 @@
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
GlobalSettingsProto.App.AUTO_RESTRICTION_ENABLED);
dumpSetting(s, p,
- Settings.Global.FORCED_APP_STANDBY_ENABLED,
- GlobalSettingsProto.App.FORCED_APP_STANDBY_ENABLED);
- dumpSetting(s, p,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
GlobalSettingsProto.App.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED);
p.end(appToken);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f740326..a9c0f00 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1298,30 +1298,40 @@
boolean makeDefault, int operation, int mode) {
enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
final String callingPackage = resolveCallingPackage();
-
+ boolean someSettingChanged = false;
// Perform the mutation.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
- return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
+ someSettingChanged = mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
UserHandle.USER_SYSTEM, name, value, null, makeDefault, true,
callingPackage, false, null,
/* overrideableByRestore */ false);
+ break;
}
case MUTATION_OPERATION_DELETE: {
- return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG,
+ someSettingChanged = mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG,
UserHandle.USER_SYSTEM, name, false, null);
+ break;
}
case MUTATION_OPERATION_RESET: {
- mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
+ someSettingChanged = mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
UserHandle.USER_SYSTEM, callingPackage, mode, null, prefix);
- } return true;
+ break;
+ }
}
}
- return false;
+ if (Settings.IPC_DATA_CACHE_ENABLED) {
+ if (someSettingChanged) {
+ Settings.Config.invalidateValueCache();
+ Settings.Config.invalidateNamespaceCache();
+ }
+ }
+
+ return someSettingChanged;
}
private HashMap<String, String> getAllConfigFlags(@Nullable String prefix) {
@@ -1482,36 +1492,45 @@
}
final String callingPackage = getCallingPackage();
+ boolean someSettingChanged = false;
// Perform the mutation.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
- return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
+ someSettingChanged = mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
callingPackage, forceNotify,
CRITICAL_GLOBAL_SETTINGS, overrideableByRestore);
+ break;
}
case MUTATION_OPERATION_DELETE: {
- return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_GLOBAL,
+ someSettingChanged = mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, forceNotify, CRITICAL_GLOBAL_SETTINGS);
+ break;
}
case MUTATION_OPERATION_UPDATE: {
- return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
+ someSettingChanged = mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
callingPackage, forceNotify, CRITICAL_GLOBAL_SETTINGS);
+ break;
}
case MUTATION_OPERATION_RESET: {
- mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_GLOBAL,
+ someSettingChanged = mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, callingPackage, mode, tag);
- } return true;
+ break;
+ }
}
}
- return false;
+ if (Settings.IPC_DATA_CACHE_ENABLED && someSettingChanged) {
+ Settings.Global.invalidateValueCache();
+ }
+
+ return someSettingChanged;
}
private PackageInfo getCallingPackageInfo(int userId) {
@@ -1954,31 +1973,39 @@
cacheFile.delete();
}
+ boolean someSettingChanged = false;
// Mutate the value.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
validateSystemSettingValue(name, value);
- return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
+ someSettingChanged = mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, value, null, false, callingPackage,
false, null, overrideableByRestore);
+ break;
}
case MUTATION_OPERATION_DELETE: {
- return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SYSTEM,
+ someSettingChanged = mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, false, null);
+ break;
}
case MUTATION_OPERATION_UPDATE: {
validateSystemSettingValue(name, value);
- return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
+ someSettingChanged = mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, value, null, false, callingPackage,
false, null);
+ break;
}
+ default:
+ Slog.e(LOG_TAG, "Unknown operation code: " + operation);
}
- Slog.e(LOG_TAG, "Unknown operation code: " + operation);
- return false;
}
+ if (Settings.IPC_DATA_CACHE_ENABLED && someSettingChanged) {
+ Settings.System.invalidateValueCache();
+ }
+ return someSettingChanged;
}
private boolean hasWriteSecureSettingsPermission() {
@@ -2969,6 +2996,9 @@
final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
if (systemSettingsState != null) {
+ if (Settings.IPC_DATA_CACHE_ENABLED) {
+ Settings.System.invalidateValueCache();
+ }
if (permanently) {
mSettingsStates.remove(systemKey);
systemSettingsState.destroyLocked(null);
@@ -2986,6 +3016,9 @@
final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
if (secureSettingsState != null) {
+ if (Settings.IPC_DATA_CACHE_ENABLED) {
+ Settings.Secure.invalidateValueCache();
+ }
if (permanently) {
mSettingsStates.remove(secureKey);
secureSettingsState.destroyLocked(null);
@@ -3140,25 +3173,25 @@
return settingsState.getSettingLocked(name);
}
- public void resetSettingsLocked(int type, int userId, String packageName, int mode,
+ public boolean resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
- resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
+ return resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
null);
}
- public void resetSettingsLocked(int type, int userId, String packageName, int mode,
+ public boolean resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag, @Nullable String prefix) {
final int key = makeKey(type, userId);
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState == null) {
- return;
+ return false;
}
banConfigurationIfNecessary(type, prefix, settingsState);
+ boolean someSettingChanged = false;
switch (mode) {
case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
- boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
if ((tag != null && !tag.equals(setting.getTag()))
@@ -3179,7 +3212,6 @@
case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
- boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
@@ -3200,7 +3232,6 @@
case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
for (String name : settingsState.getSettingNamesLocked()) {
- boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
@@ -3228,7 +3259,6 @@
case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
- boolean someSettingChanged = false;
if (prefix != null && !setting.getName().startsWith(prefix)) {
continue;
}
@@ -3249,6 +3279,7 @@
}
} break;
}
+ return someSettingChanged;
}
public void removeSettingsForPackageLocked(String packageName, int userId) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index db7032e..01740319 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -285,7 +285,6 @@
Settings.Global.FANCY_IME_ANIMATIONS,
Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
- Settings.Global.FORCED_APP_STANDBY_ENABLED,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
Settings.Global.FSTRIM_MANDATORY_INTERVAL,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b4598bf..0c97989 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -369,6 +369,9 @@
<!-- Permission needed to test wallpapers supporting ambient mode -->
<uses-permission android:name="android.permission.AMBIENT_WALLPAPER" />
+ <!-- Permission needed to test wallpaper read methods -->
+ <uses-permission android:name="android.permission.READ_WALLPAPER_INTERNAL" />
+
<!-- Permission required to test ContentResolver caching. -->
<uses-permission android:name="android.permission.CACHE_CONTENT" />
@@ -796,12 +799,19 @@
<!-- Permission required for CTS test - CtsPackageInstallTestCases-->
<uses-permission android:name="android.permission.GET_APP_METADATA" />
+ <!-- Permission required for CTS test - CtsHealthConnectDeviceTestCases -->
+ <uses-permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA" />
+ <uses-permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA" />
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
<!-- Permissions required for CTS test - CtsBroadcastRadioTestCases -->
<uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
+ <!-- Permission required for CTS test - ActivityCaptureCallbackTests -->
+ <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/res/values-mk/strings.xml b/packages/Shell/res/values-mk/strings.xml
index 0856198..93d4d52 100644
--- a/packages/Shell/res/values-mk/strings.xml
+++ b/packages/Shell/res/values-mk/strings.xml
@@ -37,7 +37,7 @@
<string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Слика од екранот"</string>
<string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Успешно е направена слика од екранот."</string>
- <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се зачува слика од екранот."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
<string name="bugreport_info_title" msgid="2306030793918239804">"Наслов на грешката"</string>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 8f70dcc..c729b09 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -301,10 +301,13 @@
interface Callback {
/** Whether we are currently on the keyguard or not. */
- fun isOnKeyguard(): Boolean
+ @JvmDefault fun isOnKeyguard(): Boolean = false
/** Hide the keyguard and animate using [runner]. */
- fun hideKeyguardWithAnimation(runner: IRemoteAnimationRunner)
+ @JvmDefault
+ fun hideKeyguardWithAnimation(runner: IRemoteAnimationRunner) {
+ throw UnsupportedOperationException()
+ }
/* Get the background color of [task]. */
fun getBackgroundColor(task: TaskInfo): Int
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/AnimationFeatureFlags.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/AnimationFeatureFlags.kt
new file mode 100644
index 0000000..1c9dabb
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/AnimationFeatureFlags.kt
@@ -0,0 +1,6 @@
+package com.android.systemui.animation
+
+interface AnimationFeatureFlags {
+ val isPredictiveBackQsDialogAnim: Boolean
+ get() = false
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index a3ed085..e91a671 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -33,8 +33,13 @@
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import android.widget.FrameLayout
+import android.window.OnBackInvokedDispatcher
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CujType
+import com.android.systemui.animation.back.BackAnimationSpec
+import com.android.systemui.animation.back.applyTo
+import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi
+import com.android.systemui.animation.back.onBackAnimationCallbackFrom
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
@@ -55,8 +60,9 @@
constructor(
private val callback: Callback,
private val interactionJankMonitor: InteractionJankMonitor,
+ private val featureFlags: AnimationFeatureFlags,
private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
- private val isForTesting: Boolean = false
+ private val isForTesting: Boolean = false,
) {
private companion object {
private val TIMINGS = ActivityLaunchAnimator.TIMINGS
@@ -273,15 +279,16 @@
val animatedDialog =
AnimatedDialog(
- launchAnimator,
- callback,
- interactionJankMonitor,
- controller,
+ launchAnimator = launchAnimator,
+ callback = callback,
+ interactionJankMonitor = interactionJankMonitor,
+ controller = controller,
onDialogDismissed = { openedDialogs.remove(it) },
dialog = dialog,
- animateBackgroundBoundsChange,
- animatedParent,
- isForTesting,
+ animateBackgroundBoundsChange = animateBackgroundBoundsChange,
+ parentAnimatedDialog = animatedParent,
+ forceDisableSynchronization = isForTesting,
+ featureFlags = featureFlags,
)
openedDialogs.add(animatedDialog)
@@ -517,6 +524,7 @@
* Whether synchronization should be disabled, which can be useful if we are running in a test.
*/
private val forceDisableSynchronization: Boolean,
+ private val featureFlags: AnimationFeatureFlags,
) {
/**
* The DecorView of this dialog window.
@@ -778,12 +786,45 @@
// the dialog.
dialog.setDismissOverride(this::onDialogDismissed)
+ if (featureFlags.isPredictiveBackQsDialogAnim) {
+ // TODO(b/265923095) Improve animations for QS dialogs on configuration change
+ registerOnBackInvokedCallback(targetView = dialogContentWithBackground)
+ }
+
// Show the dialog.
dialog.show()
-
moveSourceDrawingToDialog()
}
+ private fun registerOnBackInvokedCallback(targetView: View) {
+ val metrics = targetView.resources.displayMetrics
+
+ val onBackAnimationCallback =
+ onBackAnimationCallbackFrom(
+ backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(metrics),
+ displayMetrics = metrics, // TODO(b/265060720): We could remove this
+ onBackProgressed = { backTransformation -> backTransformation.applyTo(targetView) },
+ onBackInvoked = { dialog.dismiss() },
+ )
+
+ val dispatcher = dialog.onBackInvokedDispatcher
+ targetView.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ dispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ onBackAnimationCallback
+ )
+ }
+
+ override fun onViewDetachedFromWindow(v: View) {
+ targetView.removeOnAttachStateChangeListener(this)
+ dispatcher.unregisterOnBackInvokedCallback(onBackAnimationCallback)
+ }
+ }
+ )
+ }
+
private fun moveSourceDrawingToDialog() {
if (decorView.viewRootImpl == null) {
// Make sure that we have access to the dialog view root to move the drawing to the
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index 3d341af..2903288 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -33,9 +33,7 @@
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
private const val FONT_ITALIC_DEFAULT_VALUE = 0f
-/**
- * Provide interpolation of two fonts by adjusting font variation settings.
- */
+/** Provide interpolation of two fonts by adjusting font variation settings. */
class FontInterpolator {
/**
@@ -61,11 +59,14 @@
var index: Int,
val sortedAxes: MutableList<FontVariationAxis>
) {
- constructor(font: Font, axes: List<FontVariationAxis>) :
- this(font.sourceIdentifier,
- font.ttcIndex,
- axes.toMutableList().apply { sortBy { it.tag } }
- )
+ constructor(
+ font: Font,
+ axes: List<FontVariationAxis>
+ ) : this(
+ font.sourceIdentifier,
+ font.ttcIndex,
+ axes.toMutableList().apply { sortBy { it.tag } }
+ )
fun set(font: Font, axes: List<FontVariationAxis>) {
sourceId = font.sourceIdentifier
@@ -86,9 +87,7 @@
private val tmpInterpKey = InterpKey(null, null, 0f)
private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())
- /**
- * Linear interpolate the font variation settings.
- */
+ /** Linear interpolate the font variation settings. */
fun lerp(start: Font, end: Font, progress: Float): Font {
if (progress == 0f) {
return start
@@ -115,27 +114,34 @@
// this doesn't take much time since the variation axes is usually up to 5. If we need to
// support more number of axes, we may want to preprocess the font and store the sorted axes
// and also pre-fill the missing axes value with default value from 'fvar' table.
- val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue ->
- when (tag) {
- // TODO: Good to parse 'fvar' table for retrieving default value.
- TAG_WGHT -> adjustWeight(
- MathUtils.lerp(
+ val newAxes =
+ lerp(startAxes, endAxes) { tag, startValue, endValue ->
+ when (tag) {
+ // TODO: Good to parse 'fvar' table for retrieving default value.
+ TAG_WGHT ->
+ adjustWeight(
+ MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- progress))
- TAG_ITAL -> adjustItalic(
- MathUtils.lerp(
+ progress
+ )
+ )
+ TAG_ITAL ->
+ adjustItalic(
+ MathUtils.lerp(
startValue ?: FONT_ITALIC_DEFAULT_VALUE,
endValue ?: FONT_ITALIC_DEFAULT_VALUE,
- progress))
- else -> {
- require(startValue != null && endValue != null) {
- "Unable to interpolate due to unknown default axes value : $tag"
+ progress
+ )
+ )
+ else -> {
+ require(startValue != null && endValue != null) {
+ "Unable to interpolate due to unknown default axes value : $tag"
+ }
+ MathUtils.lerp(startValue, endValue, progress)
}
- MathUtils.lerp(startValue, endValue, progress)
}
}
- }
// Check if we already make font for this axes. This is typically happens if the animation
// happens backward.
@@ -149,9 +155,7 @@
// This is the first time to make the font for the axes. Build and store it to the cache.
// Font.Builder#build won't throw IOException since creating fonts from existing fonts will
// not do any IO work.
- val newFont = Font.Builder(start)
- .setFontVariationSettings(newAxes.toTypedArray())
- .build()
+ val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
interpCache[InterpKey(start, end, progress)] = newFont
verFontCache[VarFontKey(start, newAxes)] = newFont
return newFont
@@ -173,26 +177,28 @@
val tagA = if (i < start.size) start[i].tag else null
val tagB = if (j < end.size) end[j].tag else null
- val comp = when {
- tagA == null -> 1
- tagB == null -> -1
- else -> tagA.compareTo(tagB)
- }
+ val comp =
+ when {
+ tagA == null -> 1
+ tagB == null -> -1
+ else -> tagA.compareTo(tagB)
+ }
- val axis = when {
- comp == 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
- FontVariationAxis(tagA, v)
+ val axis =
+ when {
+ comp == 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
+ FontVariationAxis(tagA, v)
+ }
+ comp < 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, null)
+ FontVariationAxis(tagA, v)
+ }
+ else -> { // comp > 0
+ val v = filter(tagB!!, null, end[j++].styleValue)
+ FontVariationAxis(tagB, v)
+ }
}
- comp < 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, null)
- FontVariationAxis(tagA, v)
- }
- else -> { // comp > 0
- val v = filter(tagB!!, null, end[j++].styleValue)
- FontVariationAxis(tagB, v)
- }
- }
result.add(axis)
}
@@ -202,21 +208,21 @@
// For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustWeight(value: Float) =
- coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
// For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustItalic(value: Float) =
- coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
private fun coerceInWithStep(v: Float, min: Float, max: Float, step: Float) =
- (v.coerceIn(min, max) / step).toInt() * step
+ (v.coerceIn(min, max) / step).toInt() * step
companion object {
private val EMPTY_AXES = arrayOf<FontVariationAxis>()
// Returns true if given two font instance can be interpolated.
fun canInterpolate(start: Font, end: Font) =
- start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
+ start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 5f1bb83..fdab749 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -36,8 +36,8 @@
* Currently this class can provide text style animation for text weight and text size. For example
* the simple view that draws text with animating text size is like as follows:
*
- * <pre>
- * <code>
+ * <pre> <code>
+ * ```
* class SimpleTextAnimation : View {
* @JvmOverloads constructor(...)
*
@@ -53,83 +53,63 @@
* animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
* }
* }
- * </code>
- * </pre>
+ * ```
+ * </code> </pre>
*/
-class TextAnimator(
- layout: Layout,
- private val invalidateCallback: () -> Unit
-) {
+class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
// Following two members are for mutable for testing purposes.
public var textInterpolator: TextInterpolator = TextInterpolator(layout)
- public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
- duration = DEFAULT_ANIMATION_DURATION
- addUpdateListener {
- textInterpolator.progress = it.animatedValue as Float
- invalidateCallback()
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- textInterpolator.rebase()
+ public var animator: ValueAnimator =
+ ValueAnimator.ofFloat(1f).apply {
+ duration = DEFAULT_ANIMATION_DURATION
+ addUpdateListener {
+ textInterpolator.progress = it.animatedValue as Float
+ invalidateCallback()
}
- override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
- })
- }
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ textInterpolator.rebase()
+ }
+ override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
+ }
+ )
+ }
sealed class PositionedGlyph {
- /**
- * Mutable X coordinate of the glyph position relative from drawing offset.
- */
+ /** Mutable X coordinate of the glyph position relative from drawing offset. */
var x: Float = 0f
- /**
- * Mutable Y coordinate of the glyph position relative from the baseline.
- */
+ /** Mutable Y coordinate of the glyph position relative from the baseline. */
var y: Float = 0f
- /**
- * The current line of text being drawn, in a multi-line TextView.
- */
+ /** The current line of text being drawn, in a multi-line TextView. */
var lineNo: Int = 0
- /**
- * Mutable text size of the glyph in pixels.
- */
+ /** Mutable text size of the glyph in pixels. */
var textSize: Float = 0f
- /**
- * Mutable color of the glyph.
- */
+ /** Mutable color of the glyph. */
var color: Int = 0
- /**
- * Immutable character offset in the text that the current font run start.
- */
+ /** Immutable character offset in the text that the current font run start. */
abstract var runStart: Int
protected set
- /**
- * Immutable run length of the font run.
- */
+ /** Immutable run length of the font run. */
abstract var runLength: Int
protected set
- /**
- * Immutable glyph index of the font run.
- */
+ /** Immutable glyph index of the font run. */
abstract var glyphIndex: Int
protected set
- /**
- * Immutable font instance for this font run.
- */
+ /** Immutable font instance for this font run. */
abstract var font: Font
protected set
- /**
- * Immutable glyph ID for this glyph.
- */
+ /** Immutable glyph ID for this glyph. */
abstract var glyphId: Int
protected set
}
@@ -147,20 +127,18 @@
/**
* GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
*
- * This callback is called for each glyphs just before drawing the glyphs. This function will
- * be called with the intrinsic position, size, color, glyph ID and font instance. You can
- * mutate the position, size and color for tweaking animations.
- * Do not keep the reference of passed glyph object. The interpolator reuses that object for
- * avoiding object allocations.
+ * This callback is called for each glyphs just before drawing the glyphs. This function will be
+ * called with the intrinsic position, size, color, glyph ID and font instance. You can mutate
+ * the position, size and color for tweaking animations. Do not keep the reference of passed
+ * glyph object. The interpolator reuses that object for avoiding object allocations.
*
- * Details:
- * The text is drawn with font run units. The font run is a text segment that draws with the
- * same font. The {@code runStart} and {@code runLimit} is a range of the font run in the text
- * that current glyph is in. Once the font run is determined, the system will convert characters
- * into glyph IDs. The {@code glyphId} is the glyph identifier in the font and
- * {@code glyphIndex} is the offset of the converted glyph array. Please note that the
- * {@code glyphIndex} is not a character index, because the character will not be converted to
- * glyph one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
+ * Details: The text is drawn with font run units. The font run is a text segment that draws
+ * with the same font. The {@code runStart} and {@code runLimit} is a range of the font run in
+ * the text that current glyph is in. Once the font run is determined, the system will convert
+ * characters into glyph IDs. The {@code glyphId} is the glyph identifier in the font and {@code
+ * glyphIndex} is the offset of the converted glyph array. Please note that the {@code
+ * glyphIndex} is not a character index, because the character will not be converted to glyph
+ * one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
* composed from multiple characters.
*
* Here is an example of font runs: "fin. 終わり"
@@ -193,7 +171,9 @@
*/
var glyphFilter: GlyphCallback?
get() = textInterpolator.glyphFilter
- set(value) { textInterpolator.glyphFilter = value }
+ set(value) {
+ textInterpolator.glyphFilter = value
+ }
fun draw(c: Canvas) = textInterpolator.draw(c)
@@ -208,7 +188,7 @@
* @param weight an optional text weight.
* @param textSize an optional font size.
* @param colors an optional colors array that must be the same size as numLines passed to
- * the TextInterpolator
+ * the TextInterpolator
* @param animate an optional boolean indicating true for showing style transition as animation,
* false for immediate style transition. True by default.
* @param duration an optional animation duration in milliseconds. This is ignored if animate is
@@ -237,10 +217,11 @@
if (weight >= 0) {
// Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
// memory impact, cache the typeface result.
- textInterpolator.targetPaint.typeface = typefaceCache.getOrElse(weight) {
- textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
- textInterpolator.targetPaint.typeface
- }
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
+ textInterpolator.targetPaint.typeface
+ }
}
if (color != null) {
textInterpolator.targetPaint.color = color
@@ -249,22 +230,24 @@
if (animate) {
animator.startDelay = delay
- animator.duration = if (duration == -1L) {
- DEFAULT_ANIMATION_DURATION
- } else {
- duration
- }
+ animator.duration =
+ if (duration == -1L) {
+ DEFAULT_ANIMATION_DURATION
+ } else {
+ duration
+ }
interpolator?.let { animator.interpolator = it }
if (onAnimationEnd != null) {
- val listener = object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- onAnimationEnd.run()
- animator.removeListener(this)
+ val listener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ onAnimationEnd.run()
+ animator.removeListener(this)
+ }
+ override fun onAnimationCancel(animation: Animator?) {
+ animator.removeListener(this)
+ }
}
- override fun onAnimationCancel(animation: Animator?) {
- animator.removeListener(this)
- }
- }
animator.addListener(listener)
}
animator.start()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 0448c81..341784e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -26,12 +26,8 @@
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
-/**
- * Provide text style linear interpolation for plain text.
- */
-class TextInterpolator(
- layout: Layout
-) {
+/** Provide text style linear interpolation for plain text. */
+class TextInterpolator(layout: Layout) {
/**
* Returns base paint used for interpolation.
@@ -64,12 +60,11 @@
var baseFont: Font,
var targetFont: Font
) {
- val length: Int get() = end - start
+ val length: Int
+ get() = end - start
}
- /**
- * A class represents text layout of a single run.
- */
+ /** A class represents text layout of a single run. */
private class Run(
val glyphIds: IntArray,
val baseX: FloatArray, // same length as glyphIds
@@ -79,12 +74,8 @@
val fontRuns: List<FontRun>
)
- /**
- * A class represents text layout of a single line.
- */
- private class Line(
- val runs: List<Run>
- )
+ /** A class represents text layout of a single line. */
+ private class Line(val runs: List<Run>)
private var lines = listOf<Line>()
private val fontInterpolator = FontInterpolator()
@@ -106,8 +97,8 @@
/**
* The layout used for drawing text.
*
- * Only non-styled text is supported. Even if the given layout is created from Spanned, the
- * span information is not used.
+ * Only non-styled text is supported. Even if the given layout is created from Spanned, the span
+ * information is not used.
*
* The paint objects used for interpolation are not changed by this method call.
*
@@ -122,6 +113,9 @@
shapeText(value)
}
+ var shapedText: String = ""
+ private set
+
init {
// shapeText needs to be called after all members are initialized.
shapeText(layout)
@@ -130,8 +124,8 @@
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the target paint is modified, call this method to recalculate internal
- * text layout used for interpolation.
+ * Whenever the target paint is modified, call this method to recalculate internal text layout
+ * used for interpolation.
*/
fun onTargetPaintModified() {
updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
@@ -140,8 +134,8 @@
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the base paint is modified, call this method to recalculate internal
- * text layout used for interpolation.
+ * Whenever the base paint is modified, call this method to recalculate internal text layout
+ * used for interpolation.
*/
fun onBasePaintModified() {
updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
@@ -152,11 +146,11 @@
*
* The text interpolator does not calculate all the text position by text shaper due to
* performance reasons. Instead, the text interpolator shape the start and end state and
- * calculate text position of the middle state by linear interpolation. Due to this trick,
- * the text positions of the middle state is likely different from the text shaper result.
- * So, if you want to start animation from the middle state, you will see the glyph jumps due to
- * this trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different
- * from text shape result of weight 550.
+ * calculate text position of the middle state by linear interpolation. Due to this trick, the
+ * text positions of the middle state is likely different from the text shaper result. So, if
+ * you want to start animation from the middle state, you will see the glyph jumps due to this
+ * trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different from
+ * text shape result of weight 550.
*
* After calling this method, do not call onBasePaintModified() since it reshape the text and
* update the base state. As in above notice, the text shaping result at current progress is
@@ -168,8 +162,8 @@
* animate weight from 200 to 400, then if you want to move back to 200 at the half of the
* animation, it will look like
*
- * <pre>
- * <code>
+ * <pre> <code>
+ * ```
* val interp = TextInterpolator(layout)
*
* // Interpolate between weight 200 to 400.
@@ -199,9 +193,8 @@
* // progress is 0.5
* animator.start()
* }
- * </code>
- * </pre>
- *
+ * ```
+ * </code> </pre>
*/
fun rebase() {
if (progress == 0f) {
@@ -263,69 +256,73 @@
}
var maxRunLength = 0
- lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
- val runs = baseLine.zip(targetLine) { base, target ->
-
- require(base.glyphCount() == target.glyphCount()) {
- "Inconsistent glyph count at line ${lines.size}"
- }
-
- val glyphCount = base.glyphCount()
-
- // Good to recycle the array if the existing array can hold the new layout result.
- val glyphIds = IntArray(glyphCount) {
- base.getGlyphId(it).also { baseGlyphId ->
- require(baseGlyphId == target.getGlyphId(it)) {
- "Inconsistent glyph ID at $it in line ${lines.size}"
+ lines =
+ baseLayout.zip(targetLayout) { baseLine, targetLine ->
+ val runs =
+ baseLine.zip(targetLine) { base, target ->
+ require(base.glyphCount() == target.glyphCount()) {
+ "Inconsistent glyph count at line ${lines.size}"
}
- }
- }
- val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
- val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
- val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
- val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+ val glyphCount = base.glyphCount()
- // Calculate font runs
- val fontRun = mutableListOf<FontRun>()
- if (glyphCount != 0) {
- var start = 0
- var baseFont = base.getFont(start)
- var targetFont = target.getFont(start)
- require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
- "Cannot interpolate font at $start ($baseFont vs $targetFont)"
- }
-
- for (i in 1 until glyphCount) {
- val nextBaseFont = base.getFont(i)
- val nextTargetFont = target.getFont(i)
-
- if (baseFont !== nextBaseFont) {
- require(targetFont !== nextTargetFont) {
- "Base font has changed at $i but target font has not changed."
+ // Good to recycle the array if the existing array can hold the new layout
+ // result.
+ val glyphIds =
+ IntArray(glyphCount) {
+ base.getGlyphId(it).also { baseGlyphId ->
+ require(baseGlyphId == target.getGlyphId(it)) {
+ "Inconsistent glyph ID at $it in line ${lines.size}"
+ }
+ }
}
- // Font transition point. push run and reset context.
- fontRun.add(FontRun(start, i, baseFont, targetFont))
- maxRunLength = max(maxRunLength, i - start)
- baseFont = nextBaseFont
- targetFont = nextTargetFont
- start = i
+
+ val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+ val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+ val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+ val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+
+ // Calculate font runs
+ val fontRun = mutableListOf<FontRun>()
+ if (glyphCount != 0) {
+ var start = 0
+ var baseFont = base.getFont(start)
+ var targetFont = target.getFont(start)
require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
"Cannot interpolate font at $start ($baseFont vs $targetFont)"
}
- } else { // baseFont === nextBaseFont
- require(targetFont === nextTargetFont) {
- "Base font has not changed at $i but target font has changed."
+
+ for (i in 1 until glyphCount) {
+ val nextBaseFont = base.getFont(i)
+ val nextTargetFont = target.getFont(i)
+
+ if (baseFont !== nextBaseFont) {
+ require(targetFont !== nextTargetFont) {
+ "Base font has changed at $i but target font is unchanged."
+ }
+ // Font transition point. push run and reset context.
+ fontRun.add(FontRun(start, i, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, i - start)
+ baseFont = nextBaseFont
+ targetFont = nextTargetFont
+ start = i
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start" +
+ " ($baseFont vs $targetFont)"
+ }
+ } else { // baseFont === nextBaseFont
+ require(targetFont === nextTargetFont) {
+ "Base font is unchanged at $i but target font has changed."
+ }
+ }
}
+ fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, glyphCount - start)
}
+ Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
}
- fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
- maxRunLength = max(maxRunLength, glyphCount - start)
- }
- Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
+ Line(runs)
}
- Line(runs)
- }
// Update float array used for drawing.
if (tmpPositionArray.size < maxRunLength * 2) {
@@ -357,9 +354,9 @@
if (glyphFilter == null) {
for (i in run.start until run.end) {
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
}
c.drawGlyphs(line.glyphIds, run.start, tmpPositionArray, 0, run.length, font, paint)
return
@@ -388,13 +385,14 @@
tmpPaintForGlyph.color = tmpGlyph.color
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- i - prevStart,
- font,
- tmpPaintForGlyph)
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ i - prevStart,
+ font,
+ tmpPaintForGlyph
+ )
prevStart = i
arrayIndex = 0
}
@@ -404,13 +402,14 @@
}
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- run.end - prevStart,
- font,
- tmpPaintForGlyph)
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ run.end - prevStart,
+ font,
+ tmpPaintForGlyph
+ )
}
private fun updatePositionsAndFonts(
@@ -418,9 +417,7 @@
updateBase: Boolean
) {
// Update target positions with newly calculated text layout.
- check(layoutResult.size == lines.size) {
- "The new layout result has different line count."
- }
+ check(layoutResult.size == lines.size) { "The new layout result has different line count." }
lines.zip(layoutResult) { line, runs ->
line.runs.zip(runs) { lineRun, newGlyphs ->
@@ -436,7 +433,7 @@
}
require(newFont === newGlyphs.getFont(i)) {
"The new layout has different font run." +
- " $newFont vs ${newGlyphs.getFont(i)} at $i"
+ " $newFont vs ${newGlyphs.getFont(i)} at $i"
}
}
@@ -444,7 +441,7 @@
// check new font can be interpolatable with base font.
require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
"New font cannot be interpolated with existing font. $newFont," +
- " ${run.baseFont}"
+ " ${run.baseFont}"
}
if (updateBase) {
@@ -480,14 +477,13 @@
}
// Shape the text and stores the result to out argument.
- private fun shapeText(
- layout: Layout,
- paint: TextPaint
- ): List<List<PositionedGlyphs>> {
+ private fun shapeText(layout: Layout, paint: TextPaint): List<List<PositionedGlyphs>> {
+ var text = StringBuilder()
val out = mutableListOf<List<PositionedGlyphs>>()
for (lineNo in 0 until layout.lineCount) { // Shape all lines.
val lineStart = layout.getLineStart(lineNo)
- var count = layout.getLineEnd(lineNo) - lineStart
+ val lineEnd = layout.getLineEnd(lineNo)
+ var count = lineEnd - lineStart
// Do not render the last character in the line if it's a newline and unprintable
val last = lineStart + count - 1
if (last > lineStart && last < layout.text.length && layout.text[last] == '\n') {
@@ -495,19 +491,28 @@
}
val runs = mutableListOf<PositionedGlyphs>()
- TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
- paint) { _, _, glyphs, _ ->
- runs.add(glyphs)
- }
+ TextShaper.shapeText(
+ layout.text,
+ lineStart,
+ count,
+ layout.textDirectionHeuristic,
+ paint
+ ) { _, _, glyphs, _ -> runs.add(glyphs) }
out.add(runs)
+
+ if (lineNo > 0) {
+ text.append("\n")
+ }
+ text.append(layout.text.substring(lineStart, lineEnd))
}
+ shapedText = text.toString()
return out
}
}
private fun Layout.getDrawOrigin(lineNo: Int) =
- if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
- getLineLeft(lineNo)
- } else {
- getLineRight(lineNo)
- }
+ if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
+ getLineLeft(lineNo)
+ } else {
+ getLineRight(lineNo)
+ }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
new file mode 100644
index 0000000..f3d8b17
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.back
+
+import android.util.DisplayMetrics
+import android.view.animation.Interpolator
+import android.window.BackEvent
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.util.dpToPx
+
+/** Used to convert [BackEvent] into a [BackTransformation]. */
+fun interface BackAnimationSpec {
+
+ /** Computes transformation based on a [backEvent] and sets it to [result]. */
+ fun getBackTransformation(
+ backEvent: BackEvent,
+ progressY: Float, // TODO(b/265060720): Remove progressY. Could be retrieved from backEvent
+ result: BackTransformation,
+ )
+
+ companion object
+}
+
+/** Create a [BackAnimationSpec] from [displayMetrics] and design specs. */
+fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(
+ displayMetrics: DisplayMetrics,
+ maxMarginXdp: Float,
+ maxMarginYdp: Float,
+ minScale: Float,
+ translateXEasing: Interpolator = Interpolators.STANDARD_DECELERATE,
+ translateYEasing: Interpolator = Interpolators.LINEAR,
+ scaleEasing: Interpolator = Interpolators.STANDARD_DECELERATE,
+): BackAnimationSpec {
+ val screenWidthPx = displayMetrics.widthPixels
+ val screenHeightPx = displayMetrics.heightPixels
+
+ val maxMarginXPx = maxMarginXdp.dpToPx(displayMetrics)
+ val maxMarginYPx = maxMarginYdp.dpToPx(displayMetrics)
+ val maxTranslationXByScale = (screenWidthPx - screenWidthPx * minScale) / 2
+ val maxTranslationX = maxTranslationXByScale - maxMarginXPx
+ val maxTranslationYByScale = (screenHeightPx - screenHeightPx * minScale) / 2
+ val maxTranslationY = maxTranslationYByScale - maxMarginYPx
+ val minScaleReversed = 1f - minScale
+
+ return BackAnimationSpec { backEvent, progressY, result ->
+ val direction = if (backEvent.swipeEdge == BackEvent.EDGE_LEFT) 1 else -1
+ val progressX = backEvent.progress
+
+ val ratioTranslateX = translateXEasing.getInterpolation(progressX)
+ val ratioTranslateY = translateYEasing.getInterpolation(progressY)
+ val ratioScale = scaleEasing.getInterpolation(progressX)
+
+ result.apply {
+ translateX = ratioTranslateX * direction * maxTranslationX
+ translateY = ratioTranslateY * maxTranslationY
+ scale = 1f - (ratioScale * minScaleReversed)
+ }
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt
new file mode 100644
index 0000000..c6b7073
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.back
+
+import android.util.DisplayMetrics
+
+/**
+ * SysUI transitions - Dismiss app (ST1) Return to launching surface or place of origin
+ * https://carbon.googleplex.com/predictive-back-for-apps/pages/st-1-dismiss-app
+ */
+fun BackAnimationSpec.Companion.dismissAppForSysUi(
+ displayMetrics: DisplayMetrics,
+): BackAnimationSpec =
+ BackAnimationSpec.createFloatingSurfaceAnimationSpec(
+ displayMetrics = displayMetrics,
+ maxMarginXdp = 8f,
+ maxMarginYdp = 8f,
+ minScale = 0.8f,
+ )
+
+/**
+ * SysUI transitions - Cross task (ST2) Return to previous task/app, keeping the current one open
+ * https://carbon.googleplex.com/predictive-back-for-apps/pages/st-2-cross-task
+ */
+fun BackAnimationSpec.Companion.crossTaskForSysUi(
+ displayMetrics: DisplayMetrics,
+): BackAnimationSpec =
+ BackAnimationSpec.createFloatingSurfaceAnimationSpec(
+ displayMetrics = displayMetrics,
+ maxMarginXdp = 8f,
+ maxMarginYdp = 8f,
+ minScale = 0.8f,
+ )
+
+/**
+ * SysUI transitions - Inner area dismiss (ST3) Dismiss non-detachable surface
+ * https://carbon.googleplex.com/predictive-back-for-apps/pages/st-3-inner-area-dismiss
+ */
+fun BackAnimationSpec.Companion.innerAreaDismissForSysUi(
+ displayMetrics: DisplayMetrics,
+): BackAnimationSpec =
+ BackAnimationSpec.createFloatingSurfaceAnimationSpec(
+ displayMetrics = displayMetrics,
+ maxMarginXdp = 0f,
+ maxMarginYdp = 0f,
+ minScale = 0.9f,
+ )
+
+/**
+ * SysUI transitions - Floating system surfaces (ST4)
+ * https://carbon.googleplex.com/predictive-back-for-apps/pages/st-4-floating-system-surfaces
+ */
+fun BackAnimationSpec.Companion.floatingSystemSurfacesForSysUi(
+ displayMetrics: DisplayMetrics,
+): BackAnimationSpec =
+ BackAnimationSpec.createFloatingSurfaceAnimationSpec(
+ displayMetrics = displayMetrics,
+ maxMarginXdp = 8f,
+ maxMarginYdp = 8f,
+ minScale = 0.8f,
+ )
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackTransformation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackTransformation.kt
new file mode 100644
index 0000000..49d1fb4
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackTransformation.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.back
+
+import android.view.View
+
+/**
+ * This object that represents the transformation to apply to the target. The properties of this
+ * object are mutable for performance reasons (avoid recreating this object)
+ */
+data class BackTransformation(
+ var translateX: Float = Float.NaN,
+ var translateY: Float = Float.NaN,
+ var scale: Float = Float.NaN,
+)
+
+/** Apply the transformation to the [targetView] */
+fun BackTransformation.applyTo(targetView: View) {
+ if (translateX.isFinite()) targetView.translationX = translateX
+ if (translateY.isFinite()) targetView.translationY = translateY
+ if (scale.isFinite()) {
+ targetView.scaleX = scale
+ targetView.scaleY = scale
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt
new file mode 100644
index 0000000..33d14b1
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.back
+
+import android.util.DisplayMetrics
+import android.window.BackEvent
+import android.window.OnBackAnimationCallback
+
+/**
+ * Generates an [OnBackAnimationCallback] given a [backAnimationSpec]. [onBackProgressed] will be
+ * called on each update passing the current [BackTransformation].
+ *
+ * Optionally, you can specify [onBackStarted], [onBackInvoked], and [onBackCancelled] callbacks.
+ */
+fun onBackAnimationCallbackFrom(
+ backAnimationSpec: BackAnimationSpec,
+ displayMetrics: DisplayMetrics, // TODO(b/265060720): We could remove this
+ onBackProgressed: (BackTransformation) -> Unit,
+ onBackStarted: (BackEvent) -> Unit = {},
+ onBackInvoked: () -> Unit = {},
+ onBackCancelled: () -> Unit = {},
+): OnBackAnimationCallback {
+ return object : OnBackAnimationCallback {
+ private var initialY = 0f
+ private val lastTransformation = BackTransformation()
+
+ override fun onBackStarted(backEvent: BackEvent) {
+ initialY = backEvent.touchY
+ onBackStarted(backEvent)
+ }
+
+ override fun onBackProgressed(backEvent: BackEvent) {
+ val progressY = (backEvent.touchY - initialY) / displayMetrics.heightPixels
+
+ backAnimationSpec.getBackTransformation(
+ backEvent = backEvent,
+ progressY = progressY,
+ result = lastTransformation,
+ )
+
+ onBackProgressed(lastTransformation)
+ }
+
+ override fun onBackInvoked() {
+ onBackInvoked()
+ }
+
+ override fun onBackCancelled() {
+ onBackCancelled()
+ }
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/Dimension.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dimension.kt
new file mode 100644
index 0000000..4bc9972
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dimension.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.util.DisplayMetrics
+import android.util.TypedValue
+
+/** Convert [this] number of dps to device pixels. */
+fun Number.dpToPx(context: Context): Float = dpToPx(resources = context.resources)
+
+/** Convert [this] number of dps to device pixels. */
+fun Number.dpToPx(resources: Resources): Float = dpToPx(displayMetrics = resources.displayMetrics)
+
+/** Convert [this] number of dps to device pixels. */
+fun Number.dpToPx(displayMetrics: DisplayMetrics): Float =
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, toFloat(), displayMetrics)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index 7f1c78f..e4e9c46 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -178,6 +178,9 @@
/** Flag denoting whether the customizable clocks feature is enabled. */
const val FLAG_NAME_CUSTOM_CLOCKS_ENABLED = "is_custom_clocks_feature_enabled"
+ /** Flag denoting whether the Wallpaper preview should use the full screen UI. */
+ const val FLAG_NAME_WALLPAPER_FULLSCREEN_PREVIEW = "wallpaper_fullscreen_preview"
+
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 6d970b3..3d3ccf4 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -1,7 +1,5 @@
+packages/SystemUI
--packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 9ed3bac..70b5d73 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -105,6 +105,11 @@
default void onDozingChanged(boolean isDozing) {}
/**
+ * Callback to be notified when Dreaming changes. Dreaming is stored separately from state.
+ */
+ default void onDreamingChanged(boolean isDreaming) {}
+
+ /**
* Callback to be notified when the doze amount changes. Useful for animations.
* Note: this will be called for each animation frame. Please be careful to avoid
* performance regressions.
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index 004a499..bccf53d 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia tocando neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Tocando neste smartphone"</string>
<string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia tocando neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index 004a499..bccf53d 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia tocando neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Tocando neste smartphone"</string>
<string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia tocando neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index dfb73a9..87b5a4c 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -16,58 +16,13 @@
* limitations under the License.
*/
-->
-<selector
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
- <item android:state_selected="true">
- <layer-list>
- <item
- android:left="3dp"
- android:top="3dp"
- android:right="3dp"
- android:bottom="3dp">
- <!-- We make the shapes a rounded rectangle instead of an oval so that it can animate -->
- <!-- properly into an app/dialog. -->
- <shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_fixed_width"
- android:height="@dimen/keyguard_affordance_fixed_height"/>
- <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
- </shape>
- </item>
-
- <item>
- <shape android:shape="rectangle">
- <stroke
- android:color="@color/control_primary_text"
- android:width="2dp"/>
- <size
- android:width="@dimen/keyguard_affordance_fixed_width"
- android:height="@dimen/keyguard_affordance_fixed_height"/>
- <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
- </shape>
- </item>
- </layer-list>
- </item>
-
- <item>
- <layer-list>
- <item
- android:left="3dp"
- android:top="3dp"
- android:right="3dp"
- android:bottom="3dp">
- <shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_fixed_width"
- android:height="@dimen/keyguard_affordance_fixed_height"/>
- <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
- </shape>
- </item>
- </layer-list>
- </item>
-
-</selector>
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <size
+ android:width="@dimen/keyguard_affordance_fixed_width"
+ android:height="@dimen/keyguard_affordance_fixed_height"/>
+ <corners android:radius="@dimen/keyguard_affordance_fixed_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml
new file mode 100644
index 0000000..acd2462
--- /dev/null
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2023, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_selected="true">
+ <shape android:shape="oval">
+ <stroke
+ android:color="@color/control_primary_text"
+ android:width="2dp"/>
+ <size
+ android:width="@dimen/keyguard_affordance_fixed_width"
+ android:height="@dimen/keyguard_affordance_fixed_height"/>
+ </shape>
+ </item>
+</selector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 6120863..3f95515 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -67,6 +67,7 @@
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
@@ -79,6 +80,7 @@
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b76de5a..e182a6a 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,6 +24,7 @@
android:orientation="vertical">
<LinearLayout
+ android:id="@+id/media_metadata_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
index 21d12c2..4483db8 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -27,6 +27,14 @@
android:layout_height="wrap_content"
/>
+ <com.android.systemui.media.taptotransfer.receiver.ReceiverChipRippleView
+ android:id="@+id/icon_glow_ripple"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <!-- Add a bottom margin to avoid the glow of the icon ripple from being cropped by screen
+ bounds while animating with the icon -->
<com.android.internal.widget.CachingIconView
android:id="@+id/app_icon"
android:background="@drawable/media_ttt_chip_background_receiver"
@@ -34,6 +42,7 @@
android:layout_height="@dimen/media_ttt_icon_size_receiver"
android:layout_gravity="center|bottom"
android:alpha="0.0"
+ android:layout_marginBottom="@dimen/media_ttt_receiver_icon_bottom_margin"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index fcef0d2..7f12066 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Outomaties"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen klank of vibrasie nie"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen klank of vibrasie nie en verskyn laer in gespreksafdeling"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan lui of vibreer op grond van fooninstellings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan lui of vibreer op grond van fooninstellings. Gesprekke van <xliff:g id="APP_NAME">%1$s</xliff:g> af verskyn by verstek in \'n borrel."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laat die stelsel bepaal of hierdie kennisgewing \'n klank moet maak of vibreer"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Bevorder na Verstek"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Gedegradeer na Stil"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Klein"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Groot"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Klaar"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Wysig"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Vergrootglasvensterinstellings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik om toeganklikheidkenmerke oop te maak Pasmaak of vervang knoppie in Instellings.\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
@@ -885,8 +886,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ontdoen"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Beweeg nader om op <xliff:g id="DEVICENAME">%1$s</xliff:g> te speel"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Iets is fout. Probeer weer."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Laai tans"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Luidsprekers en skerms"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Voorgestelde toestelle"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Saai uit"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mense in jou omtrek met versoenbare Bluetooth-toestelle kan na die media luister wat jy uitsaai"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Hierdie skerm sal afskakel"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batterykrag oor"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koppel jou stilus aan ’n laaier"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9ae21c1..822f156 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"የታች ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"የግራ ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"የቀኝ ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"የሥራ ቅጽበታዊ ገጽ እይታዎች በ<xliff:g id="APP">%1$s</xliff:g> መተግበሪያ ውስጥ ይቀመጣሉ"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ፋይሎች"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ራስ-ሰር"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ምንም ድምፅ ወይም ንዝረት የለም"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ምንም ድምፅ ወይም ንዝረት የለም እና በውይይት ክፍል ላይ አይታይም"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"በእርስዎ የስልክ ቅንብሮች የሚወሰን ሆኖ ሊደውል ወይም ሊነዝር ይችላል"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"በእርስዎ የስልክ ቅንብሮች የሚወሰን ሆኖ ሊደውል ወይም ሊነዝር ይችላል። የ<xliff:g id="APP_NAME">%1$s</xliff:g> አረፋ ውይይቶች በነባሪነት።"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ይህ ማሳወቂያ ድምፅ ወይም ንዝረት መደረግ ካለበት ስርዓቱ እንዲወሰን ያድርጉት"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ሁኔታ:</b> ለነባሪ ከፍ ተዋውቋል።"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ሁኔታ:</b> ወደ ዝምታ ዝቅ ተደርጓል"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"መካከለኛ"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"ትንሽ"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"ትልቅ"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ተከናውኗል"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"አርትዕ"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"የማጉያ መስኮት ቅንብሮች"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"የተደራሽነት ባህሪያትን ለመክፈት መታ ያድርጉ። ይህንን አዝራር በቅንብሮች ውስጥ ያብጁ ወይም ይተኩ።\n\n"<annotation id="link">"ቅንብሮችን አሳይ"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ከ<xliff:g id="APP_LABEL">%2$s</xliff:g> ያጫውቱ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ቀልብስ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ ለማጫወት ጠጋ ያድርጉ"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"እዚህ ለማጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ጠጋ ይበሉ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"በመጫን ላይ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ጡባዊ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"የድምጽ መጠን"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ድምጽ ማውጫዎች እና ማሳያዎች"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"የተጠቆሙ መሣሪያዎች"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ማሰራጨት እንዴት እንደሚሠራ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ስርጭት"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ይህ ማያ ገጽ ይጠፋል"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ባትሪ ይቀራል"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ብሮስፌዎን ከኃይል መሙያ ጋር ያገናኙ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 3e160c7..3daba41 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"الحد السفلى <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"الحد الأيسر <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"الحد الأيمن <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"يتم حفظ لقطات الشاشة الخاصة بالعمل في تطبيق \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"الملفات"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
@@ -449,7 +447,7 @@
<string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"تطبيقات العمل الخاصة بك متّصلة بالإنترنت من خلال <xliff:g id="VPN_APP">%1$s</xliff:g>. يمكن لمشرف تكنولوجيا المعلومات ومزوّد خدمة الشبكة الافتراضية الخاصة (VPN) رؤية أنشطة الشبكة في تطبيقات العمل، بما في ذلك الرسائل الإلكترونية وبيانات التصفُّح."</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"تطبيقاتك الشخصية متّصلة بالإنترنت من خلال <xliff:g id="VPN_APP">%1$s</xliff:g>. تظهر أنشطة الشبكة، بما في ذلك الرسائل الإلكترونية وبيانات التصفُّح، لمزوّد خدمة الشبكة الافتراضية الخاصة (VPN)."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
- <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"فتح إعدادات الشبكة الافتراضية الخاصة (VPN)"</string>
+ <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"فتح إعدادات شبكة VPN"</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"يتولّى أحد الوالدين إدارة هذا الجهاز. يمكن للوالدين عرض وإدارة معلوماتك، مثلاً التطبيقات التي تستخدمها وموقعك الجغرافي ووقت النظر إلى الشاشة."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"شبكة افتراضية خاصة"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"فتح القفل باستمرار بواسطة TrustAgent"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"تلقائي"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صوت أو اهتزاز"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في أسفل قسم المحادثات"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف."</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف. تظهر المحادثات من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاعات تلقائيًا."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"السماح للنظام بتحديد ما إذا يجب اهتزاز الجهاز أو إصدار رنين عند تلقّي هذا الإشعار"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>الحالة:</b> تمت الترقية إلى الإعداد التلقائي"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>الحالة:</b> تم خفض الترتيب إلى الوضع صامت"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"تراجع"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"عليك الاقتراب لتشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"للتشغيل هنا، عليك الاقتراب من \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"حدث خطأ. يُرجى إعادة المحاولة."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"جارٍ التحميل"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"جهاز لوحي"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"مستوى الصوت"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"مكبّرات الصوت والشاشات"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"الأجهزة المقترَحة"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"البث"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* سيتم إطفاء هذه الشاشة."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"النسبة المئوية المتبقية من شحن البطارية: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"عليك توصيل قلم الشاشة بشاحن."</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"بطارية قلم الشاشة منخفضة"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 7e330d2..16c9935 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"তলৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"বাওঁফালৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"সোঁফালৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"<xliff:g id="APP">%1$s</xliff:g> এপ্টোত কৰ্মস্থানৰ স্ক্ৰীনশ্বটসমূহ ছেভ কৰা হয়"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ফাইল"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীন ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"স্বয়ংক্ৰিয়"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"কোনো ধ্বনি অথবা কম্পন নাই"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"কোনো ধ্বনি অথবা কম্পন নাই আৰু বাৰ্তালাপ শাখাটোৰ তলৰ অংশত দেখা পোৱা যায়"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ফ’নৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ফ’নৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে। <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাৰ্তালাপ ডিফ’ল্ট হিচাপে বাবল হয়।"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"এই জাননীটোৱে ধ্বনি নে কম্পন সৃষ্টি কৰিব সেয়া ছিষ্টেমটোক নিৰ্ধাৰণ কৰিবলৈ দিয়ক"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>স্থিতি:</b> ডিফ’ল্টলৈ বৃদ্ধি কৰা হৈছে"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্থিতি:</b> নীৰৱলৈ হ্ৰাস কৰা হৈছে"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ত <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"আনডু কৰক"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে’ কৰিবলৈ ওচৰলৈ যাওক"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ইয়াত প্লে’ কৰিবলৈ, <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ ওচৰলৈ যাওক"</string>
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে\' কৰি থকা হৈছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ল’ড হৈ আছে"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"টেবলেট"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ভলিউম"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পীকাৰ আৰু ডিছপ্লে’"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"পৰামৰ্শ হিচাপে পোৱা ডিভাইচ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্ৰচাৰ"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ই স্ক্ৰীনখন অফ হ’ব"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> বেটাৰী বাকী আছে"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"আপোনাৰ ষ্টাইলাছ এটা চাৰ্জাৰৰ সৈতে সংযোগ কৰক"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ষ্টাইলাছৰ বেটাৰী কম আছে"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 192f236..0646697 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Aşağı sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sol sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sağ sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"İş skrinşotları <xliff:g id="APP">%1$s</xliff:g> tətbiqində saxlanılır"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fayllar"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Səs və ya vibrasiya yoxdur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Söhbət siyahısının aşağısında səssiz və vibrasiyasız görünür"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon ayarlarına əsasən zəng çala və ya titrəyə bilər"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon ayarlarına əsasən zəng çala və ya vibrasiya edə bilər. <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqindən söhbətlərdə defolt olaraq qabarcıq çıxır."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirişin səs çıxarması və ya vibrasiya etməsi sistem tərəfindən təyin edilsin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Defolt ayara keçirilib"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Səssiz rejimə keçirilib"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Orta"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Kiçik"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Böyük"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Hazırdır"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Redaktə edin"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Böyüdücü pəncərə ayarları"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Əlçatımlılıq funksiyalarını açmaq üçün toxunun. Ayarlarda bu düyməni fərdiləşdirin və ya dəyişdirin.\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%2$s</xliff:g> tətbiqindən oxudun"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Geri qaytarın"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxutmaq üçün yaxınlaşın"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşdırın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xəta oldu. Yenə cəhd edin."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Yüklənir"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planşet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Səs"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Dinamiklər & Displeylər"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Təklif olunan Cihazlar"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Yayım"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Bu ekran deaktiv ediləcək"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> enerji qalıb"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Qələmi adapterə qoşun"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ae59e01f..9b8bbec 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Donja ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Leva ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Desna ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Snimci ekrana za posao se čuvaju u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fajlovi"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatska"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka i vibriranja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka i vibriranja i prikazuje se u nastavku odeljka za konverzacije"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Može da zvoni ili vibrira u zavisnosti od podešavanja telefona"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Može da zvoni ili vibrira u zavisnosti od podešavanja telefona. Konverzacije iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> se podrazumevano prikazuju u oblačićima."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Neka sistem utvrdi da li ovo obaveštenje treba da emituje zvuk ili da vibrira"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Unapređeno u Podrazumevano"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Degradirano u Nečujno"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednje"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Malo"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Veliko"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Izmeni"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Podešavanja prozora za uvećanje"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za funkcije pristupačnosti. Prilagodite ili zamenite ovo dugme u Podešavanjima.\n\n"<annotation id="link">"Podešavanja"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Opozovi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite da biste puštali muziku na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Da biste puštali sadržaj ovde, približite uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo je do greške. Probajte ponovo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Učitava se"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Zvuk"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcioniše emitovanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitovanje"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ovaj ekran će se isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Uređaj na preklop se otvara"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Uređaj na preklop se obrće"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo je još<xliff:g id="PERCENTAGE">%s</xliff:g> baterije"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisaljku sa punjačem"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Nizak nivo baterije pisaljke"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 53f2ff0..3a476f4 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ніжняя граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Левая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Правая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Працоўныя здымкі экрана захаваны ў праграме \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлы"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Аўтаматычна"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без гуку ці вібрацыі"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Паказваецца без гуку ці вібрацыі ў раздзеле размоў"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"У залежнасці ад налад тэлефона магчымы званок або вібрацыя"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"У залежнасці ад налад тэлефона магчымы званок або вібрацыя. Размовы ў праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" стандартна паяўляюцца ў выглядзе ўсплывальных апавяшчэнняў."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Сістэма сама будзе вызначаць, ці трэба для гэтага апавяшчэння ўключаць гук або вібрацыю"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Стан:</b> Пазначана як стандартнае"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Стан:</b> Пераведзена ў рэжым \"Без гуку\""</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Сярэдні"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Дробны"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Вялікі"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Гатова"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Змяніць"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Налады акна лупы"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Націсніце, каб адкрыць спецыяльныя магчымасці. Рэгулюйце ці замяняйце кнопку ў Наладах.\n\n"<annotation id="link">"Прагляд налад"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" з дапамогай праграмы \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Адрабіць"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Каб прайграць мультымедыя на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", наблізьцеся да яе"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Каб прайграць тут, падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешта пайшло не так. Паўтарыце спробу."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Ідзе загрузка"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшэт"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучнасць"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Дынамікі і дысплэі"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Прылады, якія падтрымліваюцца"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляцыя"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Гэты экран будзе выключаны"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складная прылада ў раскладзеным выглядзе"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перавернутая складная прылада"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Засталося зараду: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Падключыце пяро да зараднай прылады"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 71fdfa9..de24b94 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Долна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лява граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Дясна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Екранните снимки, направени в служебния потребителски профил, се запазват в приложението „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибриране"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибриране и се показва по-долу в секцията с разговори"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може да звъни или да вибрира въз основа на настройките за телефона"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може да звъни или да вибрира според настройките за телефона. Разговорите от <xliff:g id="APP_NAME">%1$s</xliff:g> се показват като балончета по подразбиране."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Нека системата да определя дали дадено известие да се придружава от звук, или вибриране"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Състояние:</b> Повишено до основно"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Състояние:</b> Понижено до беззвучно"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> от <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Отмяна"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Преместете се по-близо, за да се възпроизведе на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"За възпроизвеждане тук се приближете до <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нещо се обърка. Опитайте отново."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Зарежда се"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Сила на звука"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Високоговорители и екрани"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени устройства"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Предаване"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Този екран ще се изключи"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Оставаща батерия: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Свържете писалката към зарядно устройство"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 9a91787..a72733c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"অটোমেটিক"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"আওয়াজ করবে না বা ভাইব্রেট হবে না"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"আওয়াজ করবে না বা ভাইব্রেট হবে না এবং কথোপকথন বিভাগের নিচের দিকে দেখা যাবে"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ফোনের সেটিংস অনুযায়ী ফোন রিং বা ভাইব্রেট হতে পারে"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ফোনের সেটিংস অনুযায়ী ফোন রিং বা ভাইব্রেট হতে পারে। <xliff:g id="APP_NAME">%1$s</xliff:g>-এর কথোপকথন সাধারণত বাবলের মতো দেখাবে।"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"এই বিজ্ঞপ্তি এলে ডিভাইস আওয়াজ করবে না ভাইব্রেট করবে তা সিস্টেমকে সেট করতে দিন"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>স্ট্যাটাস:</b> লেভেল বাড়িয়ে ডিফল্ট করা হয়েছে"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্ট্যাটাস:</b> লেভেল কমিয়ে সাইলেন্ করা হয়েছে"</string>
@@ -885,8 +887,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%2$s</xliff:g> অ্যাপে চালান"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"আগের অবস্থায় ফিরুন"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ চালাতে আরও কাছে আনুন"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"এখানে চালানোর জন্য আপনার ডিভাইস <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"লোড করা হচ্ছে"</string>
@@ -915,6 +916,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পিকার & ডিসপ্লে"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"সাজেস্ট করা ডিভাইস"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ব্রডকাস্ট কীভাবে কাজ করে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্রচার করুন"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"আশপাশে লোকজন যাদের মানানসই ব্লুটুথ ডিভাইস আছে, তারা আপনার ব্রডকাস্ট করা মিডিয়া শুনতে পারবেন"</string>
@@ -1056,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ এই স্ক্রিন বন্ধ হয়ে যাবে"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ব্যাটারির চার্জ বাকি আছে"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"কোনও চার্জারের সাথে আপনার স্টাইলাস কানেক্ট করুন"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index ef0f703..d82e269 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i pojavljuje se pri dnu odjeljka razgovora"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Može zvoniti ili vibrirati na osnovu postavki telefona"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Može zvoniti ili vibrirati na osnovu postavki telefona. Razgovori iz oblačića u aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> kao zadana opcija."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačiću prema zadanim postavkama."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Neka sistem odluči treba li se ovo obavještenje oglasiti zvukom ili vibracijom"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> je unaprijeđen u Zadano"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> je unazađen u Nečujno"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednje"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Malo"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Veliko"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite da otvorite funkcije pristupačnosti. Prilagodite ili zamijenite dugme u Postavkama.\n\n"<annotation id="link">"Postavke"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Da reproducirate ovdje, približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije uredu. Pokušajte ponovo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Zahtijeva račun s naplatom"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcionira emitiranje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitirajte"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u vašoj blizini s kompatibilnim Bluetooth uređajima mogu slušati medijske sadržaje koje emitirate"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ekran će se isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nije moguće uspostavljati pozive s ovog profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaša pravila za poslovne uređaje omogućuju vam upućivanje poziva samo s poslovnog profila"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prijeđite na poslovni profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index e41292c..308ea11 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Marge inferior <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Marge esquerre <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Marge dret <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Les captures de pantalla de treball es desen a l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxers"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automàtic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sense so ni vibració"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sense so ni vibració i es mostra més avall a la secció de converses"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pot sonar o vibrar en funció de la configuració del telèfon"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pot sonar o vibrar en funció de la configuració del telèfon. Les converses de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> es mostren com a bombolles de manera predeterminada."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Fes que el sistema determini si aquesta notificació ha d\'emetre un so o una vibració"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estat</b>: s\'ha augmentat a Predeterminat"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estat</b>: s\'ha disminuït a Silenci"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> des de l\'aplicació <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfés"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Mou més a prop per reproduir a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Per reproduir contingut aquí, apropa\'l a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"S\'ha produït un error. Torna-ho a provar."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"S\'està carregant"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tauleta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altaveus i pantalles"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositius suggerits"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emet"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Aquesta pantalla s\'apagarà"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connecta el llapis òptic a un carregador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1bf8f2e..2a01318 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Dolní okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Levý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Pravý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Pracovní snímky obrazovky se ukládají do aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Soubory"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žádný zvuk ani vibrace"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žádný zvuk ani vibrace a zobrazuje se níže v sekci konverzací"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Vyzvání nebo vibruje podle nastavení telefonu"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Vyzvání nebo vibruje podle nastavení telefonu. Konverzace z aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> mají ve výchozím nastavení podobu bublin."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Vyzvání nebo vibruje podle nastavení zařízení"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Vyzvání nebo vibruje podle nastavení zařízení. Konverzace z aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> ve výchozím nastavení bublají."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Nechat systém rozhodnout, zda má toto oznámení vydat zvuk či zavibrovat"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stav:</b> priorita zvýšena na Výchozí"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stav:</b> priorita snížena na Tiché"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Střední"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Malý"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Velký"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Hotovo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Upravit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavení okna zvětšení"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Klepnutím otevřete funkce přístupnosti. Tlačítko lze upravit nebo nahradit v Nastavení.\n\n"<annotation id="link">"Nastavení"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Vrátit zpět"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pokud chcete přehrávat na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>, přibližte se k němu"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Pokud obsah chcete přehrát na tomto zařízení, přesuňte ho blíže k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo k chybě. Zkuste to znovu."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Načítání"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hlasitost"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a displeje"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Navrhovaná zařízení"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Vyžaduje prémiový účet"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysílání"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lidé ve vašem okolí s kompatibilními zařízeními Bluetooth mohou poslouchat média, která vysíláte"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Tato obrazovka se vypne"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g> baterie"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Připojte dotykové pero k nabíječce"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Slabá baterie dotykového pera"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Z tohoto profilu nelze volat"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaše pracovní zásady vám umožňují telefonovat pouze z pracovního profilu"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Přepnout na pracovní profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavřít"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c560843..d7467b00 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nederste kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Venstre kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Højre kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Screenshots, der tages via arbejdsprofilen, gemmer i appen <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibration, og den vises længere nede i samtalesektionen"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringe eller vibrere baseret på telefonens indstillinger"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringe eller vibrere baseret på telefonens indstillinger. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som standard i bobler."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Få systemet til at afgøre, om denne notifikation skal vibrere eller afspille en lyd"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Angivet som Standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Angivet som Lydløs"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Fortryd"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ryk tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"For at afspille her skal enheden tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noget gik galt. Prøv igen."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Indlæser"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lydstyrke"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Højttalere og skærme"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Foreslåede enheder"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Sådan fungerer udsendelser"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Udsendelse"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ *Denne skærm slukkes"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri tilbage"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Slut din styluspen til en oplader"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4013a3d..0b01f15 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Unterer Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linker Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechter Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Mit einem Arbeitsprofil aufgenommene Screenshots werden in der App „<xliff:g id="APP">%1$s</xliff:g>“ gespeichert"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dateien"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Kein Ton und keine Vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Kein Ton und keine Vibration, erscheint weiter unten im Bereich „Unterhaltungen“"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kann klingeln oder vibrieren, abhängig von den Telefoneinstellungen"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kann klingeln oder vibrieren, je nach Telefoneinstellungen. Unterhaltungen von <xliff:g id="APP_NAME">%1$s</xliff:g> werden standardmäßig als Bubble angezeigt."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Das System entscheiden lassen, ob bei dieser Benachrichtigung ein Ton oder eine Vibration ausgegeben wird"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status</b>: auf „Standard“ hochgestuft"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status</b>: auf „Lautlos“ herabgestuft"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> über <xliff:g id="APP_LABEL">%2$s</xliff:g> wiedergeben"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Rückgängig machen"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gehe für die Wiedergabe näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ heran"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Für eine Wiedergabe auf diesem Gerät muss es näher bei <xliff:g id="DEVICENAME">%1$s</xliff:g> sein"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wiedergabe läuft auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
- <string name="media_transfer_failed" msgid="7955354964610603723">"Es gab ein Problem. Versuch es noch einmal."</string>
+ <string name="media_transfer_failed" msgid="7955354964610603723">"Ein Fehler ist aufgetreten. Versuch es noch einmal."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Wird geladen"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"Tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lautstärke"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Lautsprecher & Displays"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Vorgeschlagene Geräte"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Nachricht an alle"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Dieses Display wird dann ausgeschaltet"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akku bei <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Schließe deinen Eingabestift an ein Ladegerät an"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c1188ed..0db8cfb 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Αυτόματο"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Χωρίς ήχο ή δόνηση"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου. Οι συζητήσεις από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εμφανίζονται σε συννεφάκι από προεπιλογή."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Επιτρέψτε στο σύστημα να αποφασίσει αν αυτή η ειδοποίηση θα αναπαράγει έναν ήχο ή θα ενεργοποιήσει τη δόνηση της συσκευής"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Κατάσταση:</b> Προάχθηκε σε Προεπιλογή"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Κατάσταση:</b> Υποβιβάστηκε σε Αθόρυβη"</string>
@@ -885,8 +887,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Αναίρεση"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Πλησιάστε για αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Για να γίνει αναπαραγωγή εδώ, μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Φόρτωση"</string>
@@ -915,6 +916,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Ηχεία και οθόνες"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Προτεινόμενες συσκευές"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Πώς λειτουργεί η μετάδοση"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Μετάδοση"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Οι άνθρωποι με συμβατές συσκευές Bluetooth που βρίσκονται κοντά σας μπορούν να ακούσουν το μέσο που μεταδίδετε."</string>
@@ -1056,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Αυτή η οθόνη θα απενεργοποιηθεί"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Απομένει το <xliff:g id="PERCENTAGE">%s</xliff:g> της μπαταρίας"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Συνδέστε τη γραφίδα σε έναν φορτιστή"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index dc4eecc..8f6b9b9 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"May ring or vibrate based on device settings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"May ring or vibrate based on device settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Have the system determine if this notification should make sound or vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promoted to default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> demoted to silent"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"To play here, move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requires premium account"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1058,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Can\'t call from this profile"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3fa3fa7..8c4e66c 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"May ring or vibrate based on device settings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"May ring or vibrate based on device settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Have the system determine if this notification should make sound or vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Promoted to Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Demoted to Silent"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
@@ -914,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & Displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested Devices"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requires premium account"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting"</string>
@@ -1057,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Can\'t call from this profile"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index dc4eecc..8f6b9b9 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"May ring or vibrate based on device settings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"May ring or vibrate based on device settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Have the system determine if this notification should make sound or vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promoted to default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> demoted to silent"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"To play here, move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requires premium account"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1058,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Can\'t call from this profile"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index dc4eecc..8f6b9b9 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"May ring or vibrate based on device settings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"May ring or vibrate based on device settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Have the system determine if this notification should make sound or vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promoted to default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> demoted to silent"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"To play here, move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requires premium account"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1058,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Can\'t call from this profile"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 0a3cf41..34bf569 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"May ring or vibrate based on device settings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"May ring or vibrate based on device settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Have the system determine if this notification should make sound or vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Promoted to Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Demoted to Silent"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation>""</string>
@@ -914,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & Displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested Devices"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requires premium account"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting"</string>
@@ -1057,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Can\'t call from this profile"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8af2620..d4bbb3f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Límite inferior: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Límite izquierdo: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Límite derecho: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Las capturas de pantalla de trabajo se guardan en la app de <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones."</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Puede sonar o vibrar en función de la configuración del teléfono."</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Puede sonar o vibrar en función de la configuración del teléfono. Conversaciones de la burbuja de <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Dejar que el sistema determine si esta notificación debe emitir un sonido o una vibración"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> Se promovió a Predeterminada"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> Descendió de nivel a Silenciada"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediano"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeño"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Listo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de ampliación"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Presiona para abrir las funciones de accesibilidad. Personaliza o cambia botón en Config.\n\n"<annotation id="link">"Ver config"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducir <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate para reproducir en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para reproducir aquí, acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se produjo un error. Vuelve a intentarlo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bocinas y pantallas"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisión"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta pantalla se apagará"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable siendo desplegado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable siendo girado"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batería restante"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu pluma stylus a un cargador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4437160..db0b4b0 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite inferior"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite izquierdo"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite derecho"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Las capturas de pantalla de trabajo se guardan en la aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Archivos"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sin sonido ni vibración, y se muestra más abajo en la sección de conversaciones"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Puede sonar o vibrar según los ajustes del teléfono"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Puede sonar o vibrar según los ajustes del teléfono. Las conversaciones de <xliff:g id="APP_NAME">%1$s</xliff:g> aparecen como burbujas de forma predeterminada."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Haz que el sistema determine si con esta notificación el dispositivo debe sonar o vibrar"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> cambio a Predeterminado"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> cambio a Silencio"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediano"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeño"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Listo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de la lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir funciones de accesibilidad. Personaliza o sustituye este botón en Ajustes.\n\n"<annotation id="link">"Ver ajustes"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir contenido ahí"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para reproducirlo, acércate al dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altavoces y pantallas"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Sugerencias de dispositivos"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emisión"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta pantalla se apagará"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batería restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu lápiz óptico a un cargador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3b6a0af..8171ddd9 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alapiir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasak piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Parem piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Töö ekraanipildid salvestatakse rakendusse <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaatne"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ilma heli ja vibreerimiseta"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ilma heli ja vibreerimiseta, kuvatakse vestluste jaotises allpool"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Võib telefoni seadete põhjal heliseda või vibreerida"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Võib telefoni seadete põhjal heliseda või vibreerida. Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> vestlused kuvatakse vaikimisi mullis."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laske süsteemil määrata, kas selle märguande puhul peaks esitama heli või vibreerima"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Olek:</b> määrati prioriteet Vaikimisi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Olek:</b> määrati prioriteet Vaikne"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Võta tagasi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Liikuge lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Siin esitamiseks minge seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Midagi läks valesti. Proovige uuesti."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Laadimine"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tahvelarvuti"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Helitugevus"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kõlarid ja ekraanid"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Soovitatud seadmed"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Ülekanne"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ See ekraan lülitatakse välja"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Volditava seadme lahtivoltimine"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Volditava seadme ümberpööramine"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akutase on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ühendage elektronpliiats laadijaga"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 783a157..6f49d06 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Beheko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ezkerreko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Eskuineko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Laneko pantaila-argazkiak <xliff:g id="APP">%1$s</xliff:g> aplikazioan gordetzen dira"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxategiak"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikoa"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du tonurik jotzen edo dar-dar egiten"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketen atalaren behealdean agertzen da"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Tonua joko du, edo dar-dar egingo, telefonoaren ezarpenen arabera"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Tonua joko du, edo dar-dar egingo, telefonoaren ezarpenen arabera. Modu lehenetsian, <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko elkarrizketak burbuila gisa agertzen dira."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ezarri sistemak zehaztu dezala jakinarazpen honek soinua edo dardara egin behar duen ala ez"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"Lehenetsi gisa ezarri da <b>egoera:</b>"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"Soinurik gabeko modura aldatu da <b>egoera:</b>"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> bidez"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desegin"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gertura ezazu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzeko"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Hemen erreproduzitzeko, hurbildu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Arazoren bat izan da. Saiatu berriro."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Kargatzen"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tableta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Bolumena"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%% <xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bozgorailuak eta pantailak"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Iradokitako gailuak"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Iragarri"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Pantaila itzali egingo da"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> geratzen da"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Konektatu arkatza kargagailu batera"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index df99cdf..f46d67b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"مرز پایین <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"مرز سمت چپ <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"مرز سمت راست <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"نماگرفتهای نمایه کاری در برنامه <xliff:g id="APP">%1$s</xliff:g> ذخیره میشوند"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ضبطکننده صفحهنمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحهنمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحهنمایش"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صدا یا لرزش"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صدا و لرزش در پایین بخش مکالمه نشان داده میشود"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"بسته به تنظیمات ممکن است تلفن زنگ بزند یا لرزش داشته باشد"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"بسته به تنظیمات ممکن است تلفن زنگ بزند یا لرزش داشته باشد. مکالمههای <xliff:g id="APP_NAME">%1$s</xliff:g> بهطور پیشفرض در حبابک نشان داده میشوند."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"بسته به تنظیمات دستگاه ممکن است زنگ بزند یا بلرزد"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"بسته به تنظیمات دستگاه ممکن است زنگ بزند یا بلرزد. مکالمههای <xliff:g id="APP_NAME">%1$s</xliff:g> بهطور پیشفرض در حبابک نشان داده میشوند."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"سیستم را تنظیم کنید که تشخیص دهد اعلان صدا و لرزش داشته باشد یا نه"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>وضعیت:</b> به «پیشفرض» ارتقا یافت"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>وضعیت:</b> به «بیصدا» تنزل یافت"</string>
@@ -887,13 +885,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%2$s</xliff:g> پخش کنید"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"واگرد"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"برای پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g> به دستگاه نزدیکتر شوید"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیکتر شوید"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"درحال بار کردن"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"رایانه لوحی"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
@@ -917,8 +913,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"میزان صدا"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"بلندگوها و نمایشگرها"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"دستگاههای پیشنهادی"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"حساب ممتاز لازم است"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همهفرتستی چطور کار میکند"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"همهفرستی"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"افرادی که در اطرافتان دستگاههای Bluetooth سازگار دارند میتوانند به رسانهای که همهفرستی میکنید گوش کنند"</string>
@@ -1060,8 +1056,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ این صفحهنمایش خاموش خواهد شد"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"دستگاه تاشو درحال باز شدن"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"دستگاه تاشو درحال چرخش به اطراف"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> باتری باقی مانده است"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"قلم را به شارژر وصل کنید"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"باتری قلم ضعیف است"</string>
+ <string name="video_camera" msgid="7654002575156149298">"دوربین ویدیویی"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"نمیتوانید از این نمایه تماس بگیرید"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"خطمشی کاری شما فقط به برقراری تماس ازطریق نمایه کاری اجازه میدهد"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"رفتن به نمایه کاری"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"بستن"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 879508c..ffb420d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alareuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasen reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Oikea reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Työprofiilin kuvakaappaukset tallennetaan sovellukseen: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaattinen"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ei ääntä tai värinää"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ei ääntä tai värinää ja näkyy alempana keskusteluosiossa"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Voi soida tai väristä puhelimen asetuksista riippuen"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Voi soida tai väristä puhelimen asetuksista riippuen. Näistä keskusteluista (<xliff:g id="APP_NAME">%1$s</xliff:g>) syntyy oletuksena kuplia."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Järjestelmä valitsee, kuuluuko tästä ilmoituksesta ääntä tai väriseekö se"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Tila:</b> valittu oletusarvoiseksi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Tila:</b> hiljennetty"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="APP_LABEL">%2$s</xliff:g>)"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Kumoa"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Siirry lähemmäs, jotta <xliff:g id="DEVICENAME">%1$s</xliff:g> voi toistaa tämän"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Siirry lähemmäs laitetta (<xliff:g id="DEVICENAME">%1$s</xliff:g>) toistaaksesi täällä"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Jotain meni pieleen. Yritä uudelleen."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Latautuminen"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tabletti"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Äänenvoimakkuus"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kaiuttimet ja näytöt"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ehdotetut laitteet"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Lähetys"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Tämä näyttö sammutetaan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkua jäljellä <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Yhdistä näyttökynä laturiin"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 39ab915..006cce8 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Les captures d\'écran du profil professionnel sont enregistrées dans l\'application <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, et s\'affiche plus bas dans la section des conversations"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Peut sonner ou vibrer, selon les paramètres du téléphone"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Peut sonner ou vibrer, selon les paramètres du téléphone. Conversations des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g> par défaut."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faire en sorte que le système détermine si cette notification devrait émettre un son ou vibrer"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>État :</b> élevé à la catégorie Par défaut"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> abaissé à la catégorie Silencieux"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous pour faire jouer le contenu sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Pour faire jouer le contenu ici, rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
+ <string name="media_transfer_failed" msgid="7955354964610603723">"Une erreur s\'est produite. Réessayez."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Chargement en cours…"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablette"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Haut-parleurs et écrans"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Appareils suggérés"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Diffusion"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Cet écran va s\'éteindre"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Charge restante de la pile : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a8e0cb4..d9267c9 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Les captures d\'écran du profil professionnel sont enregistrées dans l\'appli <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ni son, ni vibreur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ni son, ni vibreur ; s\'affiche plus bas dans la section des conversations"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Son ou vibreur, selon les paramètres du téléphone"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Son ou vibreur, selon les paramètres du téléphone. Les conversations provenant de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'affichent sous forme de bulles par défaut."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laisser le système déterminer si cette notification doit être accompagnée d\'un son ou d\'une vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>État :</b> Élevée à la catégorie \"Par défaut\""</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> Abaissée à la catégorie \"Silencieux\""</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> depuis <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous de votre <xliff:g id="DEVICENAME">%1$s</xliff:g> pour y lire le contenu"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Pour lancer la lecture ici, rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>…"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Chargement…"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablette"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Enceintes et écrans"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Appareils suggérés"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annonce"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Cet écran sera désactivé"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batterie restante"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e180f60..a06ddd7 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bordo inferior: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Bordo esquerdo: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Bordo dereito: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"As capturas de pantalla do perfil de traballo gárdanse na aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ficheiros"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sen son nin vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sen son nin vibración, e aparecen máis abaixo na sección de conversas"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"O teléfono pode soar ou vibrar en función da súa configuración"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Poderían facer que o teléfono soe ou vibre en función da súa configuración. Conversas desde a burbulla da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Fai que o sistema determine se a notificación debe emitir un son ou unha vibración"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> ascendeuse a Predeterminada"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> o nivel diminuíuse a Silencioso"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfacer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Achega o dispositivo para reproducir o contido en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para reproducir o contido aquí, achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Produciuse un erro. Téntao de novo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tableta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altofalantes e pantallas"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos suxeridos"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Difusión"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Desactivarase esta pantalla"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batería restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta o lapis óptico a un cargador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"O lapis óptico ten pouca batería"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d866a96..687d1af 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"નીચેની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ડાબી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"જમણી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ઑફિસના સ્ક્રીનશૉટ <xliff:g id="APP">%1$s</xliff:g> ઍપમાં સાચવવામાં આવે છે"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ફાઇલો"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકોર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ઑટોમૅટિક રીતે"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી અને વાતચીત વિભાગમાં તે વધુ નીચેની દિશાએ દેખાય છે"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ફોન સેટિંગના આધારે રિંગ અથવા વાઇબ્રેટ થઈ શકે છે"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ફોન સેટિંગના આધારે રિંગ અથવા વાઇબ્રેટ થઈ શકે છે. ડિફૉલ્ટ તરીકે <xliff:g id="APP_NAME">%1$s</xliff:g> બબલની વાતચીત."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ડિવાઇસના સેટિંગના આધારે રિંગ અથવા વાઇબ્રેટ થઈ શકે છે"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ડિવાઇસના સેટિંગના આધારે રિંગ અથવા વાઇબ્રેટ થઈ શકે છે. ડિફૉલ્ટ તરીકે <xliff:g id="APP_NAME">%1$s</xliff:g> બબલની વાતચીત."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"આ નોટિફિકેશન સાઉન્ડ અથવા વાઇબ્રેટ કરી શકશે કે નહીં તે સિસ્ટમને નક્કી કરવા દો"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>સ્ટેટસ:</b> ડિફૉલ્ટ તરીકે બઢતી આપવામાં આવી"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>સ્ટેટસ:</b> સાઇલન્ટ પર અવનત કરવામાં આવ્યું"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"મધ્યમ"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"નાનું"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"મોટું"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"થઈ ગયું"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ફેરફાર કરો"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"મેગ્નિફાયર વિન્ડોના સેટિંગ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ઍક્સેસિબિલિટી સુવિધાઓ ખોલવા માટે ટૅપ કરો. સેટિંગમાં આ બટનને કસ્ટમાઇઝ કરો અથવા બદલો.\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> પર <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"છેલ્લો ફેરફાર રદ કરો"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવા માટે વધુ નજીક ખસેડો"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"અહીં ચલાવવા માટે, <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક લાવો"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"લોડ થઈ રહ્યું છે"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ટૅબ્લેટ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"વૉલ્યૂમ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"સ્પીકર અને ડિસ્પ્લે"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"સૂચવેલા ડિવાઇસ"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Premium એકાઉન્ટ જરૂરી છે"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"બ્રોડકાસ્ટ પ્રક્રિયાની કામ કરવાની રીત"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"બ્રોડકાસ્ટ કરો"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"સુસંગત બ્લૂટૂથ ડિવાઇસ ધરાવતા નજીકના લોકો તમે જે મીડિયા બ્રોડકાસ્ટ કરી રહ્યાં છો તે સાંભળી શકે છે"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ આ સ્ક્રીન બંધ થઈ જશે"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ અનફોલ્ડ કરવામાં આવી રહ્યું છે"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ ફ્લિપ કરવામાં આવી રહ્યું છે"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> બૅટરી બાકી છે"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"તમારા સ્ટાઇલસને ચાર્જર સાથે કનેક્ટ કરો"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"સ્ટાઇલસની બૅટરીમાં ચાર્જ ઓછો છે"</string>
+ <string name="video_camera" msgid="7654002575156149298">"વીડિયો કૅમેરા"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"આ પ્રોફાઇલ પરથી કૉલ કરી શકતા નથી"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"તમારી ઑફિસની પૉલિસી તમને માત્ર ઑફિસની પ્રોફાઇલ પરથી જ ફોન કૉલ કરવાની મંજૂરી આપે છે"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 330b6f1..555b3d7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"निचले किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"बाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"दाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"वर्क प्रोफ़ाइल से लिए गए स्क्रीनशॉट, <xliff:g id="APP">%1$s</xliff:g> ऐप्लिकेशन में सेव किए गए हैं"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"अपने-आप"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"किसी तरह की आवाज़ या वाइब्रेशन न हो"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"इससे किसी तरह की आवाज़ या वाइब्रेशन नहीं होता और बातचीत, सेक्शन में सबसे नीचे दिखती है"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"फ़ोन की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फ़ोन की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है. <xliff:g id="APP_NAME">%1$s</xliff:g> में होने वाली बातचीत, डिफ़ॉल्ट रूप से बबल के तौर पर दिखती है."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टम को यह तय करने की अनुमति दें कि इस सूचना के मिलने पर आवाज़ हो या वाइब्रेशन हो"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिति:</b> लेवल बढ़ाकर, डिफ़ॉल्ट के तौर पर सेट किया गया"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिति:</b> लेवल घटाकर, साइलेंट पर सेट किया गया"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"छोटा"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"बड़ा"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"हो गया"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"बदलाव करें"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ज़ूम करने की सुविधा वाली विंडो से जुड़ी सेटिंग"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सुलभता सुविधाएं खोलने के लिए टैप करें. सेटिंग में, इस बटन को बदलें या अपने हिसाब से सेट करें.\n\n"<annotation id="link">"सेटिंग देखें"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> पर, <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"पहले जैसा करें"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चलाने के लिए, अपने डिवाइस को उसके पास ले जाएं"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"मीडिया ट्रांसफ़र करने के लिए, <xliff:g id="DEVICENAME">%1$s</xliff:g> के करीब जाएं"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"लोड हो रहा है"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"टैबलेट"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"वॉल्यूम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर और डिसप्ले"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सुझाए गए डिवाइस"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करें"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ यह स्क्रीन बंद हो जाएगी"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फ़ोल्ड किया जा सकने वाला डिवाइस अनफ़ोल्ड किया जा रहा है"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फ़ोल्ड किया जा सकने वाला डिवाइस पलटा जा रहा है"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"अपने स्टाइलस को चार्ज करें"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c15fabf..7e0ba00 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i prikazuje se pri dnu odjeljka razgovora"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Možda će zvoniti ili vibrirati, ovisno o postavkama telefona"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Možda će zvoniti ili vibrirati, ovisno o postavkama telefona. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačiću prema zadanim postavkama."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačiću prema zadanim postavkama."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Neka sustav odredi treba li obavijest najaviti zvukom ili vibracijom"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promaknuta u zadanu"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> prebačena u bešumnu"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednja"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Mala"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Velika"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za otvaranje značajki pristupačnosti. Prilagodite ili zamijenite taj gumb u postavkama.\n\n"<annotation id="link">"Pregledajte postavke"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite se radi reprodukcije na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Da biste reproducirali ovdje, približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije u redu. Pokušajte ponovo."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i zasloni"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Zahtijeva račun s naplatom"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako emitiranje funkcionira"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitiranje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u blizini s kompatibilnim Bluetooth uređajima mogu slušati medije koje emitirate"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ovaj će se zaslon isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo je <xliff:g id="PERCENTAGE">%s</xliff:g> baterije"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Slaba baterija pisaljke"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nije moguće uspostavljati pozive s ovog profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaša pravila za poslovne uređaje omogućuju vam upućivanje poziva samo s poslovnog profila"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prijeđite na poslovni profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 39deae7..4c8c988 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alsó rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Bal oldali rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Jobb oldali rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"A munkahelyi képernyőképeket a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásba menti a rendszer"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fájlok"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikus"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nincs hang és rezgés"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nincs hang és rezgés, továbbá lejjebb jelenik meg a beszélgetések szakaszában"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"A telefonbeállítások alapján csöröghet és rezeghet"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"A telefonbeállítások alapján csöröghet és rezeghet. A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásban lévő beszélgetések alapértelmezés szerint buborékban jelennek meg."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"A rendszer határozza meg, hogy ez az értesítés adjon-e ki hangot, illetve rezegjen-e"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Állapot:</b> alapértelmezettre állítva"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Állapot:</b> némára állítva"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> lejátszása innen: <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Visszavonás"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Menjen közelebb, ha itt szeretné lejátszani: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ha szeretné itt lejátszani, helyezkedjen közelebb a következőhöz: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hiba történt. Próbálkozzon újra."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Betöltés…"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"táblagép"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hangerő"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hangfalak és kijelzők"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Javasolt eszközök"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Közvetítés"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ A képernyő kikapcsol"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkumulátor töltöttségi szintje: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tegye töltőre az érintőceruzát"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f2e10d4..370ce823 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ներքևի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ձախ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Աջ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Աշխատանքային սքրինշոթները պահվում են «<xliff:g id="APP">%1$s</xliff:g>» հավելվածում"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ֆայլեր"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Ավտոմատ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Առանց ձայնի կամ թրթռոցի"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Առանց ձայնի և թրթռոցի, հայտնվում է զրույցների ցանկի ներքևում"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Կարող է զնգալ կամ թրթռալ (հեռախոսի կարգավորումներից կախված)"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Կարող է զնգալ կամ թրթռալ (հեռախոսի կարգավորումներից կախված)։ <xliff:g id="APP_NAME">%1$s</xliff:g>-ի զրույցներն ըստ կանխադրման հայտնվում են ամպիկների տեսքով։"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Թող համակարգն ավտոմատ որոշի՝ արդյոք այս ծանուցումը ձայնով, թե թրթռոցով է պետք մատուցել"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Կարգավիճակը․</b> բարձրացվել է և դարձել կանխադրված"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Կարգավիճակը․</b> իջեցվել է և դարձել անձայն"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Միջին"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Փոքր"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Մեծ"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Պատրաստ է"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Փոփոխել"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Խոշորացույցի պատուհանի կարգավորումներ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Հատուկ գործառույթները բացելու համար հպեք։ Անհատականացրեք այս կոճակը կարգավորումներում։\n\n"<annotation id="link">"Կարգավորումներ"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="APP_LABEL">%2$s</xliff:g> հավելվածից"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Հետարկել"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ավելի մոտ եկեք՝ <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում նվագարկելու համար"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Այստեղ նվագարկելու համար մոտեցեք <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքին"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Բեռնվում է"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"պլանշետ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ձայնի ուժգնություն"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Բարձրախոսներ և էկրաններ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Առաջարկվող սարքեր"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Հեռարձակում"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Այս էկրանը կանջատվի"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ձեր ստիլուսը միացրեք լիցքավորիչի"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 93ac4fe..bd1f48b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Batas bawah <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Batas kiri <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Batas kanan <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Screenshot dengan profil kerja disimpan di aplikasi <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"File"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatis"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tidak ada suara atau getaran"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tidak ada suara atau getaran dan ditampilkan lebih rendah di bagian percakapan"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Dapat berdering atau bergetar berdasarkan setelan ponsel"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Dapat berdering atau bergetar berdasarkan setelan ponsel. Percakapan dari balon <xliff:g id="APP_NAME">%1$s</xliff:g> secara default."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Biarkan sistem menentukan apakah notifikasi ini akan berbunyi atau bergetar"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Dipromosikan menjadi Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Didemosikan menjadi Senyap"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> dari <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Urungkan"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Dekatkan untuk memutar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Untuk memutar di sini, dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Terjadi error. Coba lagi."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Memuat"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker & Layar"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Perangkat yang Disarankan"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siaran"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Layar ini akan dinonaktifkan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Baterai tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hubungkan stilus ke pengisi daya"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index aa76263..cd924f2 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Neðri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vinstri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Hægri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Vinnuskjámyndir eru vistaðar í forritinu <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Skrár"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Sjálfvirk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ekkert hljóð eða titringur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ekkert hljóð eða titringur og birtist neðar í samtalshluta"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Gæti hringt eða titrað eftir stillingum símans"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Gæti hringt eða titrað eftir stillingum símans. Samtöl á <xliff:g id="APP_NAME">%1$s</xliff:g> birtast sjálfkrafa í blöðru."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Láta kerfið ákvarða hvort hljóð eða titringur fylgir þessari tilkynningu"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Staða:</b> gerð sjálfgefin"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Staða:</b> var gerð þögul"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> í <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Afturkalla"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Færðu nær til að spila í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Farðu nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Eitthvað fór úrskeiðis. Reyndu aftur."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Hleður"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"spjaldtölva"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hljóðstyrkur"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hátalarar og skjáir"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Tillögur að tækjum"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Útsending"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Slökkt verður á þessum skjá"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> hleðsla eftir á rafhlöðu"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tengdu pennann við hleðslutæki"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e3cca72..531ac20 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inferiore, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite sinistro, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite destro, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Gli screenshot acquisiti nel profilo di lavoro sono salvati nell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"File"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatico"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nessun suono o vibrazione"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Può suonare o vibrare in base alle impostazioni del telefono"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Può suonare o vibrare in base alle impostazioni del telefono. Le conversazioni di <xliff:g id="APP_NAME">%1$s</xliff:g> appaiono come bolla per impostazione predefinita."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del dispositivo. Conversazioni dalla bolla <xliff:g id="APP_NAME">%1$s</xliff:g> per impostaz. predefinita."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Fai stabilire al sistema se questa notifica deve emettere suoni o vibrazioni"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stato:</b> promossa a Predefinita"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stato:</b> retrocessa a Silenziosa"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medio"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Piccolo"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Fine"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifica"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Impostazioni della finestra di ingrandimento"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tocca per aprire funzioni di accessibilità. Personalizza o sostituisci il pulsante in Impostazioni.\n\n"<annotation id="link">"Vedi impostazioni"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> da <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annulla"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Avvicinati per riprodurre su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Per riprodurre qui i contenuti, avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Si è verificato un errore. Riprova."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Caricamento in corso…"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker e display"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivi consigliati"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Occorre un account premium"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annuncio"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Le persone vicine a te che hanno dispositivi Bluetooth compatibili possono ascoltare i contenuti multimediali che stai trasmettendo"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Questo schermo verrà disattivato"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pieghevole che viene aperto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pieghevole che viene capovolto"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteria rimanente"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connetti lo stilo a un caricabatterie"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Batteria stilo in esaurimento"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Impossibile chiamare da questo profilo"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Le norme di lavoro ti consentono di fare telefonate soltanto dal profilo di lavoro"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 5b55241..926e2aa 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"באופן אוטומטי"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ללא צליל או רטט"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ללא צליל או רטט ומופיעה למטה בקטע התראות השיחה"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות הטלפון"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות הטלפון. שיחות מהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מופיעות בבועות כברירת מחדל."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"אפשר לתת למערכת לקבוע אם ההתראה הזאת צריכה להיות מלווה בצליל או ברטט"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>הסטטוס:</b> הועלה בדרגה ל\'ברירת מחדל\'"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>הסטטוס:</b> הורד בדרגה ל\'שקט\'"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"בינוני"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"קטן"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"גדול"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"סיום"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"עריכה"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ההגדרות של חלון ההגדלה"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string>
@@ -885,8 +886,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> מ-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ביטול"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"צריך להתקרב כדי להפעיל מדיה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"כדי להפעיל במכשיר הזה, יש להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"משהו השתבש. יש לנסות שוב."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"בטעינה"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"רמקולים ומסכים"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"הצעות למכשירים"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"שידור"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"אנשים בקרבת מקום עם מכשירי Bluetooth תואמים יכולים להאזין למדיה שמשודרת על ידך"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ המסך יכבה"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"רמת הטעינה שנותרה בסוללה: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"כדאי לחבר את הסטיילוס למטען"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"הסוללה של הסטיילוס חלשה"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 96f7758..8cd79df 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"下部の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"仕事用のスクリーンショットは <xliff:g id="APP">%1$s</xliff:g> アプリに保存されます"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ファイル"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"着信音もバイブレーションも無効になります"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"着信音もバイブレーションも無効になり会話セクションの下に表示されます"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"スマートフォンの設定を基に着信音またはバイブレーションが有効になります"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"スマートフォンの設定を基に着信音またはバイブレーションが有効になります。デフォルトでは <xliff:g id="APP_NAME">%1$s</xliff:g> からの会話がバブルとして表示されます。"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"デバイスの設定を基に着信音またはバイブレーションが有効になります"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"デバイスの設定を基に着信音またはバイブレーションが有効になります。デフォルトでは <xliff:g id="APP_NAME">%1$s</xliff:g> からの会話がふきだしで表示されます。"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"この通知を音またはバイブレーションで知らせるかどうかの自動判断"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ステータス:</b> ランクがデフォルトに上がりました"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ステータス:</b> ランクがサイレントに下がりました"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"完了"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編集"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"拡大鏡ウィンドウの設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\n\n"<annotation id="link">"設定を表示"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> を <xliff:g id="APP_LABEL">%2$s</xliff:g> で再生"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"元に戻す"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生するにはもっと近づけてください"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"このデバイスで再生するには、<xliff:g id="DEVICENAME">%1$s</xliff:g> にもっと近づけてください"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"エラーが発生しました。もう一度お試しください。"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"読み込んでいます"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"タブレット"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"スピーカーとディスプレイ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"デバイスの候補"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"プレミアム アカウントが必要です"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ブロードキャストの仕組み"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ブロードキャスト"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth 対応デバイスを持っている付近のユーザーは、あなたがブロードキャストしているメディアを聴けます"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱この画面は OFF になります"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"折りたたみ式デバイスが広げられている"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"折りたたみ式デバイスがひっくり返されている"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"バッテリー残量 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"タッチペンを充電器に接続してください"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"タッチペンのバッテリー残量が少なくなっています"</string>
+ <string name="video_camera" msgid="7654002575156149298">"ビデオカメラ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"このプロファイルからは通話を発信できません"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"仕事用ポリシーでは、通話の発信を仕事用プロファイルからのみに制限できます"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"仕事用プロファイルに切り替える"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"閉じる"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5f9b6e1..fe0a8a0 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ავტომატური"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ხმისა და ვიბრაციის გარეშე"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ხმისა და ვიბრაციის გარეშე, ჩნდება მიმოწერების სექციის ქვედა ნაწილში"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"დარეკვა ან ვიბრაცია ტელეფონის პარამეტრების მიხედვით"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"დარეკვა ან ვიბრაცია ტელეფონის პარამეტრების მიხედვით. მიმოწერები <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ბუშტიდან, ნაგულისხმევად."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"დარეკვა ან ვიბრაცია მოწყობილობის პარამეტრების მიხედვით"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"დარეკვა ან ვიბრაცია მოწყობილობის პარამეტრების მიხედვით. მიმოწერები <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ბუშტიდან, ნაგულისხმევად."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"სისტემისთვის ისეთი უფლების მინიჭება, რომ მან განსაზღვროს, ამ შეტყობინებამ ხმოვანი სიგნალი უნდა აამოქმედოს თუ ვიბრაცია"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>სტატუსი:</b> ნაგულისხმევად გარდაქმნილი"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>სტატუსი:</b> „უხმო“ სტატუსზე გადასული"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"საშუალო"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"პატარა"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"დიდი"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"მზადაა"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"რედაქტირება"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"გადიდების ფანჯრის პარამეტრები"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"შეეხეთ მარტივი წვდომის ფუნქციების გასახსნელად. მოარგეთ ან შეცვალეთ ეს ღილაკი პარამეტრებში.\n\n"<annotation id="link">"პარამეტრების ნახვა"</annotation></string>
@@ -883,11 +882,10 @@
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"გახსენით <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g>-დან"</string>
- <string name="media_transfer_undo" msgid="1895606387620728736">"მოქმედების გაუქმება"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"მოქმედ.გაუქმება"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"მიიტანეთ უფრო ახლოს, რომ დაუკრათ <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"აქ სათამაშოდ, მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს"</string>
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"უკრავს <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"იტვირთება"</string>
<string name="media_ttt_default_device_type" msgid="4457646436153370169">"ტაბლეტი"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"დინამიკები და დისპლეები"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"შემოთავაზებული მოწყობილობები"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"საჭიროა პრემიუმ-ანგარიში"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ტრანსლირების მუშაობის პრინციპი"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ტრანსლაცია"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"თქვენთან ახლოს მყოფ ხალხს თავსებადი Bluetooth მოწყობილობით შეუძლიათ თქვენ მიერ ტრანსლირებული მედიის მოსმენა"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ეს ეკრანი გამოირთვება"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"დასაკეცი მოწყობილობა იხსნება"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"დასაკეცი მოწყობილობა ტრიალებს"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"დარჩენილია ბატარეის <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"დააკავშირეთ თქვენი სტილუსი დამტენს"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"სტილუსის ბატარეა დაცლის პირასაა"</string>
+ <string name="video_camera" msgid="7654002575156149298">"ვიდეოკამერა"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ამ პროფილიდან დარეკვა ვერ ხერხდება"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"თქვენი სამსახურის წესები საშუალებას გაძლევთ, სატელეფონო ზარები განახორციელოთ მხოლოდ სამსახურის პროფილიდან"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"სამსახურის პროფილზე გადართვა"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"დახურვა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 77c586a..b2274c8 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Төменгі шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Сол жақ шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Оң жақ шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Жұмыс профилінен алынған скриншоттар <xliff:g id="APP">%1$s</xliff:g> қолданбасында сақталады."</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматты"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дыбыс не діріл болмайды."</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дыбыс не діріл болмайды, әңгімелер бөлімінің төмен жағында тұрады."</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Телефон параметрлеріне байланысты дыбыстық сигнал не діріл болуы мүмкін."</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефон параметрлеріне байланысты дыбыстық сигнал не діріл болуы мүмкін. <xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелері әдепкісінше қалқып шығады."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Хабарландыру дыбысының немесе дірілдің қосылуын жүйе анықтайтын болады"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Күйі:</b> \"Әдепкі\" санатына көтерілген"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Күйі:</b> \"Үнсіз\" санатына төмендетілген"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> қолданбасында \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Қайтару"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында музыка ойнату үшін оған жақындаңыз."</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Осы жерде ойнату үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Жүктеліп жатыр"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дыбыс деңгейі"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер мен дисплейлер"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ұсынылған құрылғылар"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Тарату"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Бұл экран өшіріледі."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Қалған батарея заряды: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index a191a14..d33b439 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"បន្ទាត់បែងចែកខាងក្រោម <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"បន្ទាត់បែងចែកខាងឆ្វេង <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"បន្ទាត់បែងចែកខាងស្ដាំ <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"រូបថតអេក្រង់ក្នុងកម្រងព័ត៌មានការងារត្រូវបានរក្សាទុកនៅក្នុងកម្មវិធី <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ឯកសារ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថតវីដេអូអេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុងដំណើរការការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ស្វ័យប្រវត្តិ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"គ្មានសំឡេង ឬការញ័រទេ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"គ្មានសំឡេងឬការញ័រ និងបង្ហាញទាបជាងនៅក្នុងផ្នែកសន្ទនា"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ទូរសព្ទ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ទូរសព្ទ។ ការសន្ទនាពីពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g> តាមលំនាំដើម។"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ឱ្យប្រព័ន្ធកំណត់ថាតើការជូនដំណឹងនេះគួរតែបន្លឺសំឡេង ឬញ័រ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ស្ថានភាព៖</b> បានដំឡើងទៅលំនាំដើម"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ស្ថានភាព៖</b> បានបញ្ចុះទៅស្ងាត់"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ពី <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ត្រឡប់វិញ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"រំកិលឱ្យកាន់តែជិត ដើម្បីចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ដើម្បីចាក់នៅទីនេះ សូមខិតទៅជិត <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុងចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"កំពុងផ្ទុក"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ថេប្លេត"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាចគ្រប់គ្រងបានទេ"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"កម្រិតសំឡេង"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ឧបករណ៍បំពងសំឡេង និងផ្ទាំងអេក្រង់"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ឧបករណ៍ដែលបានណែនាំ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ការផ្សាយ"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ អេក្រង់នេះនឹងបិទ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ឧបករណ៍អាចបត់បានកំពុងត្រូវបានលា"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ឧបករណ៍អាចបត់បានកំពុងត្រូវបានលា"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ថ្មនៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ភ្ជាប់ប៊ិករបស់អ្នកជាមួយឆ្នាំងសាក"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 652a227..e9dc769 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ಕೆಳಗಿನ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ಎಡಭಾಗದ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ಬಲಭಾಗದ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"<xliff:g id="APP">%1$s</xliff:g> ಆ್ಯಪ್ನಲ್ಲಿ ಉಳಿಸಲಾದ ಕೆಲಸದ ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳು"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ಫೈಲ್ಗಳು"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಅಧಿಸೂಚನೆ"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ಸ್ವಯಂಚಾಲಿತ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್ ಆಗುವುದಿಲ್ಲ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್ ಆಗುವುದಿಲ್ಲ, ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಕೆಳಭಾಗದಲ್ಲಿ ಗೋಚರಿಸುತ್ತದೆ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ. ಡಿಫಾಲ್ಟ್ ಆಗಿ, <xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಬಬಲ್ ಸಂಭಾಷಣೆಗಳು."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಸಾಧನ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ. ಡಿಫಾಲ್ಟ್ ಆಗಿ, <xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ ಸಂಭಾಷಣೆಗಳು."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ಈ ಅಧಿಸೂಚನೆಯು ಶಬ್ದ ಮಾಡಬೇಕೇ ಅಥವಾ ವೈಬ್ರೇಟ್ ಮಾಡಬೇಕೇ ಎಂಬುದನ್ನು ನಿರ್ಧರಿಸುವ ಅವಕಾಶವನ್ನು ಸಿಸ್ಟಂಗೆ ನೀಡಿ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ಸ್ಥಿತಿ:</b> ಡೀಫಾಲ್ಟ್ಗೆ ಬಡ್ತಿ ಹೊಂದಿದೆ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ಸ್ಥಿತಿ:</b> ಸೈಲೆಂಟ್ಗೆ ಕೆಳದರ್ಜೆಗೆ ಇಳಿದಿದೆ"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"ಮಧ್ಯಮ"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"ಚಿಕ್ಕದು"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"ದೊಡ್ಡದು"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ಮುಗಿದಿದೆ"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ಮ್ಯಾಗ್ನಿಫೈರ್ ವಿಂಡೋ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಈ ಬಟನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ ಅಥವಾ ಬದಲಾಯಿಸಿ.\n\n"<annotation id="link">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%2$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ರದ್ದುಗೊಳಿಸಿ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅದರ ಹತ್ತಿರಕ್ಕೆ ಸರಿಯಿರಿ"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು, <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಸರಿಯಿರಿ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ಟ್ಯಾಬ್ಲೆಟ್"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ವಾಲ್ಯೂಮ್"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ಸ್ಪೀಕರ್ಗಳು ಮತ್ತು ಡಿಸ್ಪ್ಲೇಗಳು"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ಸೂಚಿಸಿದ ಸಾಧನಗಳು"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"ಪ್ರೀಮಿಯಂ ಖಾತೆಯ ಅಗತ್ಯವಿದೆ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ಪ್ರಸಾರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ಪ್ರಸಾರ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ಹೊಂದಾಣಿಕೆಯಾಗುವ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಹೊಂದಿರುವ ಸಮೀಪದಲ್ಲಿರುವ ಜನರು ನೀವು ಪ್ರಸಾರ ಮಾಡುತ್ತಿರುವ ಮಾಧ್ಯಮವನ್ನು ಆಲಿಸಬಹುದು"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ಈ ಸ್ಕ್ರೀನ್ ಆಫ್ ಆಗುತ್ತದೆ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಅನ್ಫೋಲ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಸುತ್ತಲೂ ತಿರುಗಿಸಲಾಗುತ್ತಿದೆ"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ ಉಳಿದಿದೆ"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ನಿಮ್ಮ ಸ್ಟೈಲಸ್ ಅನ್ನು ಚಾರ್ಜರ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದೆ"</string>
+ <string name="video_camera" msgid="7654002575156149298">"ವೀಡಿಯೊ ಕ್ಯಾಮರಾ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ಈ ಪ್ರೊಫೈಲ್ನಿಂದ ಕರೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ನಿಮ್ಮ ಕೆಲಸದ ನೀತಿಯು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನಿಂದ ಮಾತ್ರ ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಬದಲಿಸಿ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ಮುಚ್ಚಿರಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2346774..c9d70a1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"하단 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"왼쪽 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"오른쪽 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"직장 프로필의 스크린샷은 <xliff:g id="APP">%1$s</xliff:g> 앱에 저장됩니다."</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"파일"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"자동"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"소리 또는 진동 없음"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"소리나 진동이 울리지 않으며 대화 섹션 하단에 표시됨"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"휴대전화 설정에 따라 벨소리나 진동이 울릴 수 있음"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"휴대전화 설정에 따라 벨소리나 진동이 울릴 수 있습니다. 기본적으로 <xliff:g id="APP_NAME">%1$s</xliff:g>의 대화는 대화창으로 표시됩니다."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"시스템에서 알림 시 소리 또는 진동을 사용할지 결정하도록 허용합니다."</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>상태:</b> 기본으로 높임"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>상태:</b> 무음으로 낮춤"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"보통"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"작게"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"크게"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"완료"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"수정"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"돋보기 창 설정"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"접근성 기능을 열려면 탭하세요. 설정에서 이 버튼을 맞춤설정하거나 교체할 수 있습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>에서 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"실행취소"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생하려면 기기를 더 가까이로 옮기세요."</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"여기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동하세요."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"문제가 발생했습니다. 다시 시도해 주세요."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"로드 중"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"태블릿"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"볼륨"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"스피커 및 디스플레이"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"추천 기기"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"브로드캐스트"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 이 화면이 꺼집니다."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"배터리 <xliff:g id="PERCENTAGE">%s</xliff:g> 남음"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"스타일러스를 충전기에 연결하세요"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index c05fae2..54a073e 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ылдый жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Сол жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Оң жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Жумуш скриншоттору <xliff:g id="APP">%1$s</xliff:g> колдонмосунда сакталат"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -437,7 +435,7 @@
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Саясаттарды карап көрүү"</string>
<string name="monitoring_button_view_controls" msgid="8316440345340701117">"Башкаруу элементтерин көрүү"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Бул түзмөк <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюмуна таандык.\n\nАдминистраторуңуз бул түзмөктөгү жөндөөлөрдү, корпоративдик ресурстарды пайдалануу мүмкүнчүлүгүн берген параметрлерди жана колдонмолорду, түзмөгүңүзгө байланыштуу маалыматтарды (мисалы, түзмөгүңүздүн жайгашкан жери сыяктуу) көзөмөлдөп башкара алат.\n\nТолугураак маалымат алуу үчүн IT администраторуңузга кайрылыңыз."</string>
- <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> бул түзмөк менен байланышкан маалыматты көрүп, колдонмолорду башкарып, анын жөндөөлөрүн өзгөртө алат.\n\nЭгер суроолоруңуз болсо, <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g> уюмуна кайрылыңыз."</string>
+ <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> бул түзмөк менен байланышкан маалыматты көрүп, колдонмолорду башкарып, анын параметрлерин өзгөртө алат.\n\nЭгер суроолоруңуз болсо, <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g> уюмуна кайрылыңыз."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Бул түзмөк уюмуңузга таандык.\n\nАдминистраторуңуз бул түзмөктөгү жөндөөлөрдү, корпоративдик ресурстарды пайдалануу мүмкүнчүлүгүн берген параметрлерди жана колдонмолорду, түзмөгүңүзгө байланыштуу маалыматтарды (мисалы, түзмөгүңүздүн жайгашкан жери сыяктуу) көзөмөлдөп башкара алат.\n\nТолугураак маалымат алуу үчүн IT администраторуңузга кайрылыңыз."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ишканаңыз бул түзмөккө тастыктоочу борборду орнотту. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Ишканаңыз жумуш профилиңизге тастыктоочу борборду орнотту. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string>
@@ -454,7 +452,7 @@
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ишеним агенти кулпусун ачты"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <string name="accessibility_volume_settings" msgid="1458961116951564784">"Добуштун жөндөөлөрү"</string>
+ <string name="accessibility_volume_settings" msgid="1458961116951564784">"Добуштун параметрлери"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Автоматтык коштомо жазуулар"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"Коштомо жазуулар кеңеши"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Коштомо жазуулардын үстүнө коюу"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматтык"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Үнү чыкпайт жана дирилдебейт"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Үнү чыкпайт же дирилдебейт жана сүйлөшүүлөр тизмесинин ылдый жагында көрүнөт"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Телефондун параметрлерине жараша шыңгырап же дирилдеши мүмкүн"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефондун параметрлерине жараша шыңгырап же дирилдеши мүмкүн. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жазышуулар демейки жөндөө боюнча калкып чыкма билдирмелер түрүндө көрүнөт."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Билдирменин үнүн чыгартууну же басууну тутумга тапшырыңыз"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Абалы:</b> Демейкиге өзгөрдү"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Абалы:</b> Үнсүз абалга төмөндөдү"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Орто"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Кичине"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Чоң"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Бүттү"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Түзөтүү"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Чоңойткуч терезесинин параметрлери"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Атайын мүмкүнчүлүктөрдү ачуу үчүн басыңыз. Бул баскычты Жөндөөлөрдөн өзгөртүңүз.\n\n"<annotation id="link">"Жөндөөлөрдү көрүү"</annotation></string>
@@ -847,7 +846,7 @@
<string name="controls_favorite_removed" msgid="5276978408529217272">"Бардык башкаруу элементтери өчүрүлдү"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгөртүүлөр сакталган жок"</string>
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Башка колдонмолорду көрүү"</string>
- <string name="controls_favorite_load_error" msgid="5126216176144877419">"Башкаруу элементтери жүктөлгөн жок. <xliff:g id="APP">%s</xliff:g> колдонмосуна өтүп, колдонмонун жөндөөлөрү өзгөрбөгөнүн текшериңиз."</string>
+ <string name="controls_favorite_load_error" msgid="5126216176144877419">"Башкаруу элементтери жүктөлгөн жок. <xliff:g id="APP">%s</xliff:g> колдонмосуна өтүп, колдонмонун параметрлери өзгөрбөгөнүн текшериңиз."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"Шайкеш башкаруу элементтери жеткиликсиз"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Түзмөктү башкаруу элементтерине кошуу"</string>
@@ -887,17 +886,15 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын <xliff:g id="APP_LABEL">%2$s</xliff:g> колдонмосунан ойнотуу"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Кайтаруу"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакындатыңыз"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ушул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындаңыз"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Жүктөлүүдө"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string>
- <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүн пайдалана албайсыз. Аны <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосунан башкарууга мүмкүн же мүмкүн эместигин, ошондой эле колдонмонун жөндөөлөрүнүн өзгөрүлбөгөнүн текшериңиз."</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүн пайдалана албайсыз. Аны <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосунан башкарууга мүмкүн же мүмкүн эместигин, ошондой эле колдонмонун параметрлеринин өзгөрүлбөгөнүн текшериңиз."</string>
<string name="controls_open_app" msgid="483650971094300141">"Колдонмону ачуу"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Абалы жүктөлгөн жок"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Үндүн катуулугу"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер жана дисплейлер"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Сунушталган түзмөктөр"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Кабарлоо"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Бул экран өчөт"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Батареянын кубаты: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусту кубаттаңыз"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7af21e8..fc386d6 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ຂອບເຂດທາງລຸ່ມ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ຂອບເຂດທາງຊ້າຍ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ຂອບເຂດທາງຂວາ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ຮູບໜ້າຈໍວຽກຖືກບັນທຶກຢູ່ໃນແອັບ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ໄຟລ໌"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ອັດຕະໂນມັດ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ ແລະ ປາກົດຢູ່ທາງລຸ່ມຂອງພາກສ່ວນການສົນທະນາ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າໂທລະສັບ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າໂທລະສັບ. ການສົນທະນາຈາກ <xliff:g id="APP_NAME">%1$s</xliff:g> ຈະສະແດງເປັນຟອງຕາມຄ່າເລີ່ມຕົ້ນ."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ໃຫ້ລະບົບກຳນົດວ່າການແຈ້ງເຕືອນນິ້ຄວນມີສຽງ ຫຼື ສັ່ນເຕືອນຫຼືບໍ່"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ສະຖານະ:</b> ເລື່ອນລະດັບເປັນຄ່າເລີ່ມຕົ້ນແລ້ວ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ສະຖານະ:</b> ຫຼຸດລະດັບເປັນປິດສຽງແລ້ວ"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"ປານກາງ"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"ນ້ອຍ"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"ໃຫຍ່"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ແລ້ວໆ"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ແກ້ໄຂ"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ການຕັ້ງຄ່າໜ້າຈໍຂະຫຍາຍ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ແຕະເພື່ອເປີດຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ປັບແຕ່ງ ຫຼື ປ່ຽນປຸ່ມນີ້ໃນການຕັ້ງຄ່າ.\n\n"<annotation id="link">"ເບິ່ງການຕັ້ງຄ່າ"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ຍົກເລີກ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ຍ້າຍໄປໃກ້ຂຶ້ນເພື່ອຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້, ໃຫ້ເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ຫຼາຍຂຶ້ນ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ກຳລັງໂຫຼດ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ແທັບເລັດ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ລະດັບສຽງ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ລຳໂພງ ແລະ ຈໍສະແດງຜົນ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ອຸປະກອນທີ່ແນະນຳ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ອອກອາກາດ"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ໜ້າຈໍນີ້ຈະປິດ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ອຸປະກອນທີ່ພັບໄດ້ກຳລັງກາງອອກ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ອຸປະກອນທີ່ພັກໄດ້ກຳລັງປີ້ນໄປມາ"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ແບັດເຕີຣີເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ເຊື່ອມຕໍ່ປາກກາຂອງທ່ານກັບສາຍສາກ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index cdf134c..753b8b7 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apatinė riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kairioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Dešinioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Ekrano kopijos, užfiksuotos naudojantis darbo profiliu, išsaugomos programoje „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Failai"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatinis"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Neskamba ir nevibruoja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Neskamba, nevibruoja ir rodoma apatinėje pokalbių skilties dalyje"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Gali skambėti arba vibruoti, atsižvelgiant į telefono nustatymus"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Gali skambėti arba vibruoti, atsižvelgiant į telefono nustatymus. Pokalbiai iš „<xliff:g id="APP_NAME">%1$s</xliff:g>“ debesėlio pagal numatytuosius nustatymus."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Gali skambėti arba vibruoti, atsižvelgiant į įrenginio nustatymus"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Gali skambėti arba vibruoti, atsižvelgiant į įrenginio nustatymus. Pokalbiai iš „<xliff:g id="APP_NAME">%1$s</xliff:g>“ debesėlio pagal numatytuosius nustatymus."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Nustatykite, kad sistema aptiktų, ar šis pranešimas turi skambėti, ar vibruoti"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Būsena:</b> pakeista į numatytąjį lygį"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Būsena:</b> pakeista į begarsį lygį"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Vidutinis"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Mažas"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Didelis"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Atlikta"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Redaguoti"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Didinimo lango nustatymai"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Palietę atidarykite pritaikymo neįgaliesiems funkcijas. Tinkinkite arba pakeiskite šį mygtuką nustatymuose.\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Leisti „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%2$s</xliff:g>“"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anuliuoti"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Prieikite arčiau, kad galėtumėte leisti įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Jei norite leisti čia, eikite arčiau įrenginio „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kažkas ne taip. Bandykite dar kartą."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Įkeliama"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planšetinis kompiuteris"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Garsumas"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Garsiakalbiai ir ekranai"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Siūlomi įrenginiai"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Reikalinga mokama paskyra"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transliacija"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Netoliese esantys žmonės, turintys suderinamus „Bluetooth“ įrenginius, gali klausyti jūsų transliuojamos medijos"</string>
@@ -1062,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Lankstomasis įrenginys apverčiamas"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Liko akumuliatoriaus įkrovos: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Prijunkite rašiklį prie kroviklio"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Senka rašiklio akumuliatorius"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Vaizdo kamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Negalima skambinti iš šio profilio"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pagal jūsų darbo politiką galite skambinti telefonu tik iš darbo profilio"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Perjungti į darbo profilį"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Uždaryti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 603b2b6..f2af1c1 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apakšmala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kreisā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Labā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Darba profila ekrānuzņēmumi tiek saglabāti lietotnē <xliff:g id="APP">%1$s</xliff:g>."</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automātiski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nav skaņas signāla vai vibrācijas"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nav skaņas signāla vai vibrācijas, kā arī atrodas tālāk sarunu sadaļā"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Atkarībā no tālruņa iestatījumiem var zvanīt vai vibrēt"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Atkarībā no tālruņa iestatījumiem var zvanīt vai vibrēt. Sarunas no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> pēc noklusējuma tiek parādītas burbulī."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Iestatiet, lai sistēma noteiktu, vai šim paziņojumam būs skaņa vai vibrācija"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Statuss:</b> svarīgums paaugstināts līdz noklusējumam"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statuss:</b> svarīgums pazemināts, un paziņojums tiks rādīts bez skaņas"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” no lietotnes <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Atsaukt"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pārvietojiet savu ierīci tuvāk, lai atskaņotu mūziku ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”."</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Lai atskaņotu šeit, jums jāatrodas tuvāk šai ierīcei: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Radās kļūda. Mēģiniet vēlreiz."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Notiek ielāde"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planšetdators"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Skaļums"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Skaļruņi un displeji"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ieteiktās ierīces"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Apraide"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Šis ekrāns tiks izslēgts."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Atlikušais uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pievienojiet skārienekrāna pildspalvu lādētājam"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e1280b8..1517c23 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може да ѕвони или вибрира во зависност од поставките на телефонот"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може да ѕвони или вибрира во зависност од поставките на телефонот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволете системот да определи дали известувањево треба да испушти звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> поставено на „Стандардно“"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> намалено на „Тивко“"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средно"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Мало"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Големо"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Изменете"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Поставки за прозорец за лупа"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Допрете за функциите за пристапност. Приспособете или заменете го копчево во „Поставки“.\n\n"<annotation id="link">"Прикажи поставки"</annotation></string>
@@ -885,8 +886,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Врати"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближете се за да пуштите на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"За да пуштате овде, приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Се вчитува"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени уреди"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционира емитувањето"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитување"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Луѓето во ваша близина со компатибилни уреди со Bluetooth може да ги слушаат аудиозаписите што ги емитувате"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Екранов ќе се исклучи"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостаната батерија: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поврзете го пенкалото со полнач"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 88a3514..365e660 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"സ്വയമേവ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല, സംഭാഷണ വിഭാഗത്തിന് താഴെയായി ദൃശ്യമാകും"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ്/വൈബ്രേറ്റ് ചെയ്യും"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ്/വൈബ്രേറ്റ് ചെയ്തേക്കാം. <xliff:g id="APP_NAME">%1$s</xliff:g>-ൽ നിന്നുള്ള സംഭാഷണങ്ങൾ ഡിഫോൾട്ടായി ബബിൾ ചെയ്യുന്നു."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ഉപകരണ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ് ചെയ്യും അല്ലെങ്കിൽ വൈബ്രേറ്റ് ചെയ്യും"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ഉപകരണ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ് ചെയ്യും അല്ലെങ്കിൽ വൈബ്രേറ്റ് ചെയ്യും. <xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിൽ നിന്നുള്ള സംഭാഷണങ്ങൾ ഡിഫോൾട്ടായി ബബിൾ ചെയ്യുന്നു."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ഈ അറിയിപ്പ് വരുമ്പോൾ ശബ്ദിക്കുകയാണോ വൈബ്രേറ്റ് ചെയ്യുകയാണോ വേണ്ടതെന്ന് നിർണ്ണയിക്കാൻ സിസ്റ്റത്തെ അനുവദിക്കുക"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>നില:</b> ഡിഫോൾട്ടാക്കി പ്രമോട്ട് ചെയ്തു"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>നില:</b> നിശബ്ദമാക്കി തരം താഴ്ത്തി"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"ഇടത്തരം"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"ചെറുത്"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"വലുത്"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"പൂർത്തിയായി"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"എഡിറ്റ് ചെയ്യുക"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"മാഗ്നിഫയർ വിൻഡോ ക്രമീകരണം"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ഉപയോഗസഹായി ഫീച്ചർ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ക്രമീകരണത്തിൽ ഈ ബട്ടൺ ഇഷ്ടാനുസൃതമാക്കാം, മാറ്റാം.\n\n"<annotation id="link">"ക്രമീകരണം കാണൂ"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%2$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"പഴയപടിയാക്കുക"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യാൻ അടുത്തേക്ക് നീക്കുക"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിനടുത്തേക്ക് നീക്കുക"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ലോഡ് ചെയ്യുന്നു"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"സ്പീക്കറുകളും ഡിസ്പ്ലേകളും"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"നിർദ്ദേശിച്ച ഉപകരണങ്ങൾ"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"പ്രീമിയം അക്കൗണ്ട് ആവശ്യമാണ്"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്കാസ്റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ബ്രോഡ്കാസ്റ്റ്"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"അനുയോജ്യമായ Bluetooth ഉപകരണങ്ങളോടെ സമീപമുള്ള ആളുകൾക്ക് നിങ്ങൾ ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്ന മീഡിയ കേൾക്കാനാകും"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ഈ സ്ക്രീൻ ഓഫാകും"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം അൺഫോൾഡ് ആകുന്നു"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം, കറങ്ങുന്ന വിധത്തിൽ ഫ്ലിപ്പ് ആകുന്നു"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ബാറ്ററി ചാർജ് ശേഷിക്കുന്നു"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"നിങ്ങളുടെ സ്റ്റൈലസ് ചാർജറുമായി കണക്റ്റ് ചെയ്യുക"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"സ്റ്റൈലസിന്റെ ബാറ്ററി ചാർജ് കുറവാണ്"</string>
+ <string name="video_camera" msgid="7654002575156149298">"വീഡിയോ ക്യാമറ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ഈ പ്രൊഫൈലിൽ നിന്ന് കോൾ ചെയ്യാനാകില്ല"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് മാത്രം ഫോൺ കോളുകൾ ചെയ്യാനാണ് നിങ്ങളുടെ ഔദ്യോഗിക നയം അനുവദിക്കുന്നത്"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"അടയ്ക്കുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8358164..a6194c9 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Доод талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Зүүн талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Баруун талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Ажлын дэлгэцийн агшнуудыг <xliff:g id="APP">%1$s</xliff:g> апп дээр хадгалсан"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлс"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автомат"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дуу эсвэл чичиргээ байхгүй"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дуу эсвэл чичиргээ байхгүй бөгөөд харилцан ярианы хэсгийн доод талд харагдана"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Утасны тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичирхийлж болзошгүй"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Утасны тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичирхийлж болзошгүй. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөл тохиргооны дагуу бөмбөлөг болгоно."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Энэ мэдэгдэл дуу гаргах эсвэл чичрэх эсэхийг системээр тодорхойлуулаарай"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Төлөв:</b> Өгөгдмөл болгож дэвшүүлсэн"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Төлөв:</b> Чимээгүй болгож зэрэглэлийг нь бууруулсан"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Дунд зэрэг"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Жижиг"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Том"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Болсон"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Засах"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Томруулагчийн цонхны тохиргоо"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Хандалтын онцлогуудыг нээхийн тулд товшино уу. Энэ товчлуурыг Тохиргоо хэсэгт өөрчилж эсвэл солиорой.\n\n"<annotation id="link">"Тохиргоог харах"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%2$s</xliff:g> дээр тоглуулах"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Болих"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулахын тулд төхөөрөмжөө ойртуулна уу"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g> руу ойртуулна уу"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Ачаалж байна"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дууны түвшин"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Чанга яригч ба дэлгэц"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Санал болгосон төхөөрөмжүүд"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Нэвтрүүлэлт"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Энэ дэлгэц унтарна"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> батарей үлдлээ"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Мэдрэгч үзгээ цэнэглэгчтэй холбоорой"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index caf0b0a..bbcd720 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"खालील सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"डाव्या सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"उजव्या सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ऑफिससंबंधित स्क्रीनशॉट <xliff:g id="APP">%1$s</xliff:g> अॅपमध्ये सेव्ह केले आहेत"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"फाइल"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ऑटोमॅटिक"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"आवाज किंवा व्हायब्रेशन नाही"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोन सेटिंग्जनुसार फोन रिंग किंवा व्हायब्रेट होऊ शकतो"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो. <xliff:g id="APP_NAME">%1$s</xliff:g> मधील संभाषणे बाय डीफॉल्ट बबल होतात."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ही सूचना मिळाल्यावर आवाज व्हावा की व्हायब्रेशन व्हावे ते सिस्टममध्ये नमूद करा"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिती</b> ही डीफॉल्ट म्हणून प्रमोट केली गेली"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिती</b> ला सायलंट म्हणून डीमोट केले गेले"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> मध्ये <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"पहिल्यासारखे करा"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले करण्यासाठी जवळ जा"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"येथे प्ले करण्यासाठी, <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले होत आहे"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"लोड करत आहे"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"टॅबलेट"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"व्हॉल्यूम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर आणि डिस्प्ले"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सुचवलेली डिव्हाइस"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करा"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ही स्क्रीन बंद होईल"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड करता येण्यासारखे डिव्हाइस अनफोल्ड केले जात आहे"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड करता येण्यासारखे डिव्हाइस आजूबाजूला फ्लिप केले जात आहे"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बॅटरी शिल्लक आहे"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"तुमचे स्टायलस चार्जरशी कनेक्ट करा"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"स्टायलस बॅटरी कमी आहे"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 4800990..9b9e72c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Sempadan bawah <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sempadan kiri <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sempadan kanan <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Tangkapan skrin tugasan disimpan dalam apl <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fail"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perakam Skrin"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tiada bunyi atau getaran"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tiada bunyi atau getaran dan muncul di sebelah bawah dalam bahagian perbualan"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Mungkin berbunyi atau bergetar berdasarkan tetapan telefon"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Mungkin berbunyi atau bergetar berdasarkan tetapan telefon. Perbualan daripada gelembung <xliff:g id="APP_NAME">%1$s</xliff:g> secara lalai."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Mungkin berbunyi atau bergetar berdasarkan tetapan peranti"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Mungkin berbunyi atau bergetar berdasarkan tetapan peranti. Perbualan daripada gelembung <xliff:g id="APP_NAME">%1$s</xliff:g> secara lalai."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Minta sistem menentukan jika pemberitahuan ini patut menghasilkan bunyi atau getaran"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Dinaikkan Taraf kepada Lalai"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Diturunkan Taraf kepada Senyap"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Sederhana"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Kecil"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Besar"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Selesai"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Tetapan tetingkap penggadang"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketik untuk membuka ciri kebolehaksesan. Sesuaikan/gantikan butang ini dalam Tetapan.\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> daripada <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Buat asal"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Alihkan lebih dekat untuk bermain pada<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Untuk bermain di sini, bergerak lebih dekat kepada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Memuatkan"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Kelantangan"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Pembesar Suara & Paparan"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Peranti yang Dicadangkan"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Memerlukan akaun premium"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara siaran berfungsi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siarkan"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang berdekatan anda dengan peranti Bluetooth yang serasi boleh mendengar media yang sedang anda siarkan"</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Skrin ini akan dimatikan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Peranti boleh lipat dibuka"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Peranti boleh lipat diterbalikkan"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateri tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Sambungkan stilus anda kepada pengecas"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateri stilus lemah"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Tidak dapat membuat panggilan daripada profil ini"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Dasar kerja anda membenarkan anda membuat panggilan telefon hanya daripada profil kerja"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tukar kepada profil kerja"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 54eb158..21ebda9 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"အောက်ခြေအနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ဘယ်ဘက်အနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ညာဘက်အနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"အလုပ်နှင့်ဆိုင်သော ဖန်သားပြင်ဓာတ်ပုံများကို <xliff:g id="APP">%1$s</xliff:g> အက်ပ်တွင် သိမ်းသည်"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ဖိုင်များ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ဖန်သားပြင် ရိုက်ကူးမှု"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"စကရင်ရိုက်ကူးမှု အပြီးသတ်နေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"အလိုအလျောက်"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ဖုန်းဆက်တင်ပေါ် အခြေခံပြီး အသံမြည် (သို့) တုန်ခါနိုင်သည်။ <xliff:g id="APP_NAME">%1$s</xliff:g> မှ စကားဝိုင်းများကို ပူဖောင်းကွက်ဖြင့် အလိုအလျောက်ပြသည်။"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ဤအကြောင်းကြားချက်က အသံ သို့မဟုတ် တုန်ခါမှု ပေးရန် သင့်/မသင့်ကို စနစ်က ဆုံးဖြတ်ပါစေ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>အခြေအနေ-</b> မူရင်းသို့ ချိန်ညှိထားသည်"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>အခြေအနေ-</b> အသံတိတ်ခြင်းသို့ ပြန်ချိန်ညှိထားသည်"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"အလတ်"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"အသေး"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"အကြီး"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ပြီးပြီ"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ပြင်ရန်"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"မှန်ဘီလူးဝင်းဒိုး ဆက်တင်များ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ရန် တို့ပါ။ ဆက်တင်များတွင် ဤခလုတ်ကို စိတ်ကြိုက်ပြင်ပါ (သို့) လဲပါ။\n\n"<annotation id="link">"ဆက်တင်များ ကြည့်ရန်"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%2$s</xliff:g> တွင် ဖွင့်ပါ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"နောက်ပြန်ရန်"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ရန် အနီးသို့ရွှေ့ပါ"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ဤနေရာတွင် ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့ ရွှေ့ပါ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ဖွင့်နေသည်"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"တက်ဘလက်"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"အသံအတိုးအကျယ်"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"စပီကာနှင့် ဖန်သားပြင်များ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"အကြံပြုထားသော စက်ပစ္စည်းများ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ထုတ်လွှင့်ခြင်း"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ဤဖန်သားပြင်ကို ပိတ်လိုက်မည်"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်သေးသည်"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"စတိုင်လပ်စ်ကို အားသွင်းကိရိယာနှင့် ချိတ်ဆက်ခြင်း"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 70dc961..30fa917 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nedre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Venstre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Høyre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Jobbrelaterte skjermdumper lagres i <xliff:g id="APP">%1$s</xliff:g>-appen"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibrering"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibrering, og vises lavere i samtaledelen"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringe eller vibrere basert på telefoninnstillingene"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringe eller vibrere basert på telefoninnstillingene. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> lager bobler som standard."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"La systemet velge om dette varselet skal lage lyd eller vibrere"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Oppgradert til standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Nedgradert til lydløst"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Middels"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Liten"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Stor"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Ferdig"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Endre"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Innstillinger for forstørringsvindu"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trykk for å åpne tilgj.funksjoner. Tilpass eller bytt knappen i Innstillinger.\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> fra <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Angre"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytt nærmere for å spille av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"For å spille av her, gå nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noe gikk galt. Prøv på nytt."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Laster inn"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"nettbrett"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Høyttalere og skjermer"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Foreslåtte enheter"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Kringkasting"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Denne skjermen slås av"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En sammenleggbar enhet blir brettet ut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En sammenleggbar enhet blir snudd"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri gjenstår"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koble pekepennen til en lader"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 1aa4e43..4cc7c2f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"फेदबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"बायाँ किनाराबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"दायाँ किनाराबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"कार्य प्रोफाइल प्रयोग गरी लिइएका स्क्रिनसटहरू <xliff:g id="APP">%1$s</xliff:g> एपमा सेभ गरिन्छन्"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"स्वचालित"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"बज्दैन पनि, भाइब्रेट पनि हुँदैन"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"बज्दैन पनि, भाइब्रेट पनि हुँदैन र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोनको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोनको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> का वार्तालापहरू डिफल्ट रूपमा बबलमा देखाइन्छन्।"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टमलाई यो सूचना आउँदा ध्वनि बज्नु पर्छ वा कम्पन हुनु पर्छ भन्ने कुराको निधो गर्न दिनुहोस्"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिति:</b> सूचनालाई महत्त्वपूर्ण ठानी डिफल्ट मोडमा सेट गरिएको छ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिति:</b> सूचनालाई कम महत्त्वपूर्ण ठानी साइलेन्ट मोडमा सेट गरिएको छ"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"सानो"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"ठुलो"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"सम्पन्न भयो"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"सम्पादन गर्नुहोस्"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"म्याग्निफायर विन्डोसम्बन्धी सेटिङ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सर्वसुलभता कायम गर्ने सुविधा खोल्न ट्याप गर्नुहोस्। सेटिङमा गई यो बटन कस्टमाइज गर्नुहोस् वा बदल्नुहोस्।\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%2$s</xliff:g> मा बजाउनुहोस्"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"अन्डू गर्नुहोस्"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गर्न आफ्नो डिभाइस नजिकै लैजानुहोस्"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"यो डिभाइसमा प्ले गर्न <xliff:g id="DEVICENAME">%1$s</xliff:g> को अझ नजिक जानुहोस्"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"लोड हुँदै छ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ट्याब्लेट"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"भोल्युम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पिकर तथा डिस्प्लेहरू"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सिफारिस गरिएका डिभाइसहरू"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"प्रसारण"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ यो स्क्रिन अफ हुने छ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड गर्न मिल्ने डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड गर्न मिल्ने डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ब्याट्री बाँकी छ"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"आफ्नो स्टाइलस चार्जरमा कनेक्ट गर्नुहोस्"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9aaa56d..8f0d864 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ondergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linkergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechtergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Werkscreenshots worden opgeslagen in de <xliff:g id="APP">%1$s</xliff:g>-app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Bestanden"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen geluid of trilling"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen geluid of trilling en wordt lager in het gedeelte met gesprekken getoond"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan overgaan of trillen op basis van de telefooninstellingen"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan overgaan of trillen op basis van de telefooninstellingen. Gesprekken uit <xliff:g id="APP_NAME">%1$s</xliff:g> worden standaard als bubbels getoond."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kan overgaan of trillen op basis van de apparaatinstellingen"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kan overgaan of trillen op basis van de apparaatinstellingen. Gesprekken uit <xliff:g id="APP_NAME">%1$s</xliff:g> worden standaard als bubbels weergegeven."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Het systeem laten bepalen of deze melding geluid moet maken of moet trillen"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> opgeschaald naar Standaard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> verlaagd naar Stil"</string>
@@ -887,13 +885,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ongedaan maken"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Houd dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> om af te spelen"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ga dichter naar <xliff:g id="DEVICENAME">%1$s</xliff:g> toe om hier af te spelen"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Laden"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
@@ -917,8 +913,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers en schermen"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Voorgestelde apparaten"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Je hebt een premium account nodig"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Uitzending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mensen bij jou in de buurt met geschikte bluetooth-apparaten kunnen luisteren naar de media die je uitzendt"</string>
@@ -1060,8 +1056,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Dit scherm gaat uit"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Opvouwbaar apparaat wordt uitgevouwen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Opvouwbaar apparaat wordt gedraaid"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g> batterijlading"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Verbind je stylus met een oplader"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Batterij van stylus bijna leeg"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Je kunt niet bellen vanuit dit profiel"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Op basis van je werkbeleid kun je alleen bellen vanuit het werkprofiel"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Overschakelen naar werkprofiel"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sluiten"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index d7c17a2..b179bc5 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ନିମ୍ନ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ବାମ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ଡାହାଣ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ୱାର୍କ ସ୍କ୍ରିନସଟଗୁଡ଼ିକୁ <xliff:g id="APP">%1$s</xliff:g> ଆପରେ ସେଭ କରାଯାଇଛି"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ଫାଇଲଗୁଡ଼ିକ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରିନ୍ ରେକର୍ଡ୍ ସେସନ୍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ସ୍ୱଚାଳିତ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ ଏବଂ ବାର୍ତ୍ତାଳାପ ବିଭାଗର ନିମ୍ନରେ ଦେଖାଯାଏ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ଫୋନ ସେଟିଂସ ଆଧାରରେ ରିଙ୍ଗ କିମ୍ବା ଭାଇବ୍ରେଟ ହୋଇପାରେ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ଫୋନ୍ ସେଟିଂସ୍ ଆଧାରରେ ରିଙ୍ଗ କିମ୍ବା ଭାଇବ୍ରେଟ୍ ହୋଇପାରେ। <xliff:g id="APP_NAME">%1$s</xliff:g>ରୁ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଡିଫଲ୍ଟ ଭାବରେ ବବଲ୍ ହୁଏ।"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ଏହି ବିଜ୍ଞପ୍ତି ପ୍ରାପ୍ତ ହେବା ସମୟରେ ସାଉଣ୍ଡ ହେବା ଉଚିତ ନା ଭାଇବ୍ରେସନ୍ ତାହା ସିଷ୍ଟମକୁ ସ୍ଥିର କରିବାକୁ ଦିଅନ୍ତୁ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ସ୍ଥିତି:</b> ଡିଫଲ୍ଟକୁ ପ୍ରମୋଟ୍ କରାଯାଇଛି"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ସ୍ଥିତି:</b> ନୀରବକୁ ଡିମୋଟ୍ କରାଯାଇଛି"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ରୁ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ପ୍ଲେ କରିବା ପାଇଁ ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ଏଠାରେ ପ୍ଲେ କରିବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g> ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ପ୍ଲେ ହେଉଛି"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ଲୋଡ ହେଉଛି"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ଟାବଲେଟ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ଭଲ୍ୟୁମ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ସ୍ପିକର ଏବଂ ଡିସପ୍ଲେଗୁଡ଼ିକ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ପ୍ରସ୍ତାବିତ ଡିଭାଇସଗୁଡ଼ିକ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ବ୍ରଡକାଷ୍ଟ"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ଏହି ସ୍କ୍ରିନ ବନ୍ଦ ହୋଇଯିବ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବେଟେରୀ ଚାର୍ଜ ବାକି ଅଛି"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ଏକ ଚାର୍ଜର ସହ ଆପଣଙ୍କ ଷ୍ଟାଇଲସକୁ କନେକ୍ଟ କରନ୍ତୁ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a6fd6eb..d8ffabf 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ਖੱਬੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ਸੱਜੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ਕਾਰਜ ਸਕ੍ਰੀਨਸ਼ਾਟਾਂ ਨੂੰ <xliff:g id="APP">%1$s</xliff:g> ਐਪ ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ਫ਼ਾਈਲਾਂ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ਸਵੈਚਲਿਤ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਹੇਠਲੇ ਪਾਸੇ ਦਿਸਦੀਆਂ ਹਨ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ਫ਼ੋਨ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ਫ਼ੋਨ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ। ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਤੌਰ \'ਤੇ <xliff:g id="APP_NAME">%1$s</xliff:g> ਤੋਂ ਗੱਲਾਂਬਾਤਾਂ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ।"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ਸਿਸਟਮ ਨੂੰ ਨਿਰਧਾਰਤ ਕਰਨ ਦਿਓ ਕਿ ਇਸ ਸੂਚਨਾ ਲਈ ਕੋਈ ਧੁਨੀ ਵਜਾਉਣੀ ਚਾਹੀਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਵਧਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ਤੋਂ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ਅਣਕੀਤਾ ਕਰੋ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਉਣ ਲਈ ਨੇੜੇ ਲਿਜਾਓ"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ, <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਲਿਆਓ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ਟੈਬਲੈੱਟ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ਅਵਾਜ਼"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ਸਪੀਕਰ ਅਤੇ ਡਿਸਪਲੇਆਂ"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ਸੁਝਾਏ ਗਏ ਡੀਵਾਈਸ"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ਪ੍ਰਸਾਰਨ"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ਇਹ ਸਕ੍ਰੀਨ ਬੰਦ ਹੋ ਜਾਵੇਗੀ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਆਲੇ-ਦੁਆਲੇ ਫਲਿੱਪ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ ਬਾਕੀ"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ਆਪਣੇ ਸਟਾਈਲਸ ਨੂੰ ਚਾਰਜਰ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 592c334..f25f1a6 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Przycięcie dolnej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Przycięcie lewej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Przycięcie prawej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Służbowe zrzuty ekranu są zapisywane w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Pliki"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatycznie"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez dźwięku i wibracji"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brak dźwięku i wibracji, wyświetla się niżej w sekcji rozmów"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Może włączać dzwonek lub wibracje w zależności od ustawień telefonu"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Może włączać dzwonek lub wibracje w zależności od ustawień telefonu. Rozmowy z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> są domyślnie wyświetlane jako dymki."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Pozwól systemowi decydować, czy o powiadomieniu powinien informować dźwięk czy wibracja"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stan:</b> zmieniony na Domyślny"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stan:</b> zmieniono na Ciche"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> w aplikacji <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Cofnij"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Przysuń się bliżej, aby odtwarzać na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Aby zagrać tutaj, przysuń bliżej urządzenie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Coś poszło nie tak. Spróbuj ponownie."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Wczytuję"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Głośność"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Głośniki i wyświetlacze"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Proponowane urządzenia"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisja"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Ekran się wyłączy"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g> baterii"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Podłącz rysik do ładowarki"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Słaba bateria w rysiku"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c35a7f8..fd5328f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode vibrar ou tocar com base nas configurações do smartphone"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode vibrar ou tocar com base nas configurações do smartphone. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se a notificação resultará em som ou vibração"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promovida a Padrão"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> rebaixada a Silenciosa"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluído"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
@@ -885,9 +886,8 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para abrir aqui, aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Tocando no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string>
<string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index f483ef7..5efafc7 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sem som ou vibração"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sem som ou vibração e aparece na parte inferior na secção de conversas."</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode tocar ou vibrar com base nas definições do telemóvel."</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode tocar ou vibrar com base nas definições do telemóvel. As conversas da app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem como um balão por predefinição."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Pode tocar ou vibrar com base nas definições do dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Pode tocar ou vibrar com base nas definições do dispositivo. As conversas da app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem como um balão por predefinição."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se esta notificação deve emitir um som ou uma vibração"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> promovida para Predefinida"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> despromovida para Silenciosa"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluir"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Definições da janela da lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir funcionalidades de acessibilidade. Personal. ou substitua botão em Defin.\n\n"<annotation id="link">"Ver defin."</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anular"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime-se para reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para reproduzir aqui, aproxime-se do <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"A carregar"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altifalantes e ecrãs"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Requer uma conta premium"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmissão"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas de si com dispositivos Bluetooth compatíveis podem ouvir o conteúdo multimédia que está a transmitir"</string>
@@ -1058,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável a ser virado ao contrário"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de bateria restante"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ligue a caneta stylus a um carregador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da caneta stylus fraca"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Câmara de vídeo"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Não é possível ligar a partir deste perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"A sua Política de Trabalho só lhe permite fazer chamadas telefónicas a partir do perfil de trabalho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Mudar para perfil de trabalho"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c35a7f8..fd5328f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode vibrar ou tocar com base nas configurações do smartphone"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode vibrar ou tocar com base nas configurações do smartphone. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se a notificação resultará em som ou vibração"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promovida a Padrão"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> rebaixada a Silenciosa"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluído"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
@@ -885,9 +886,8 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para abrir aqui, aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Tocando no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string>
<string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 9196f47..c23098a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Marginea de jos la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Marginea stângă la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Marginea dreaptă la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Capturile de ecran pentru serviciu sunt salvate în aplicația <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fișiere"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automat"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Fără sunet sau vibrații"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Poate să sune sau să vibreze, în funcție de setările telefonului"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Poate să sune sau să vibreze, în funcție de setările telefonului. Conversațiile din balonul <xliff:g id="APP_NAME">%1$s</xliff:g> în mod prestabilit."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Solicită-i sistemului să stabilească dacă această notificare e sonoră sau cu vibrații."</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stare:</b> promovată la prestabilită"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stare:</b> setată ca Silențioasă"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediu"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Mic"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Mare"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Gata"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editează"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Setările ferestrei de mărire"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atinge ca să deschizi funcțiile de accesibilitate. Personalizează sau înlocuiește butonul în setări.\n\n"<annotation id="link">"Vezi setările"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Redă <xliff:g id="SONG_NAME">%1$s</xliff:g> în <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anulează"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Apropie-te pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Pentru a reda conținutul aici, apropie-te de <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încearcă din nou."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Se încarcă"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tabletă"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verifică aplicația"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Difuzoare și afișaje"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispozitive sugerate"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmite"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Acest ecran se va dezactiva"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterie rămasă"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conectează-ți creionul la un încărcător"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 804f9af..0f1b895 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Граница снизу: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Граница слева: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Граница справа: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Скриншоты сохраняются в приложении \"<xliff:g id="APP">%1$s</xliff:g>\" в рабочем профиле"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлы"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматически"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука и вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука или вибрации, появляется в нижней части списка разговоров"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Звонок или вибрация в зависимости от настроек телефона"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Звонок или вибрация в зависимости от настроек телефона. Разговоры из приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" по умолчанию появляются в виде всплывающего чата"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Звонок или вибрация в зависимости от настроек устройства"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Звонок или вибрация в зависимости от настроек устройства. Разговоры из приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" по умолчанию появляются в виде всплывающего чата."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Система будет сама определять, включать ли звуковой сигнал или вибрацию для уведомления"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> повышено до уровня \"По умолчанию\""</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> понижено до уровня \"Без звука\""</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средняя"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Маленькая"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Большая"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ОК"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Изменить"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Настройка окна лупы"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Нажмите, чтобы открыть спец. возможности. Настройте или замените эту кнопку в настройках.\n\n"<annotation id="link">"Настройки"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Отменить"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Чтобы начать трансляцию на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", подойдите к нему ближе."</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Чтобы начать воспроизведение здесь, подойдите ближе к устройству (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Произошла ошибка. Повторите попытку."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Загрузка…"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Громкость"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки и дисплеи"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Рекомендуемые устройства"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Требуется премиум-аккаунт"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работают трансляции"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляция"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Находящиеся рядом с вами люди с совместимыми устройствами Bluetooth могут слушать медиафайлы, которые вы транслируете."</string>
@@ -1060,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Этот экран отключится"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складное устройство в разложенном виде"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перевернутое складное устройство"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Уровень заряда батареи: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поставьте стилус на зарядку."</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Низкий заряд батареи стилуса"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Невозможно совершить звонок из этого профиля"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Согласно правилам вашей организации вы можете совершать телефонные звонки только из рабочего профиля."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в рабочий профиль"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыть"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 518d184..9ad90af 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"පහළ සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"වම් සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"දකුණු සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"වැඩ තිර රූ <xliff:g id="APP">%1$s</xliff:g> යෙදුම තුළ සුරැකෙයි"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ගොනු"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ස්වයංක්රිය"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"හඬක් හෝ කම්පනයක් නැත"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"හඬක් හෝ කම්පනයක් නැති අතර සංවාද කොටසේ පහළම දිස් වේ"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"දුරකථන සැකසීම් මත පදනම්ව නාද කිරීමට හෝ කම්පනය කිරීමට හැකිය"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"දුරකථන සැකසීම් මත පදනම්ව නාද කිරීමට හෝ කම්පනය කිරීමට හැකිය. <xliff:g id="APP_NAME">%1$s</xliff:g> වෙතින් සංවාද පෙරනිමියෙන් බුබුළු දමයි"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"උපාංග සැකසීම් මත පදනම්ව නාද වීමට හෝ කම්පනය විය හැක"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"උපාංග සැකසීම් මත පදනම්ව නාද වීමට හෝ කම්පනය විය හැක. <xliff:g id="APP_NAME">%1$s</xliff:g> වෙතින් සංවාද පෙරනිමියෙන් බුබුළු දමයි."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"මෙම දැනුම් දීම ශබ්දයක් හෝ කම්පනයක් ඇති කළ යුතු ද යන්න පද්ධතිය මගින් තීරණය කර තිබේද"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>තත්ත්වය:</b> පෙරනිමි වෙත ප්රවර්ධනය කරන ලදි"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>තත්ත්වය:</b> නිශ්ශබ්ද වෙත පහත දමන ලදි"</string>
@@ -887,13 +885,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"පසුගමනය කරන්න"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කිරීමට වඩාත් ළං වන්න"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"මෙහි වාදනය කිරීම සඳහා, <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත සමීප වන්න"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"පූරණය වේ"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ටැබ්ලටය"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
@@ -917,8 +913,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"හඬ පරිමාව"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ස්පීකර් සහ සංදර්ශක"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"යෝජිත උපාංග"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"පාරිතෝෂික ගිණුමක් අවශ්යයි"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්රියා කරන ආකාරය"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"විකාශනය"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ගැළපෙන බ්ලූටූත් උපාංග සහිත ඔබ අවට සිටින පුද්ගලයින්ට ඔබ විකාශනය කරන මාධ්යයට සවන් දිය හැකිය"</string>
@@ -1060,8 +1056,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ මෙම තිරය ක්රියා විරහිත වනු ඇත"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> බැටරිය ඉතිරිව ඇත"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ඔබේ පන්හිඳ චාජරයකට සම්බන්ධ කරන්න"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"පන්හිඳ බැටරිය අඩුයි"</string>
+ <string name="video_camera" msgid="7654002575156149298">"වීඩියෝ කැමරාව"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"මෙම පැතිකඩෙන් ඇමතීමට නොහැක"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ඔබේ වැඩ ප්රතිපත්තිය ඔබට කාර්යාල පැතිකඩෙන් පමණක් දුරකථන ඇමතුම් ලබා ගැනීමට ඉඩ සලසයි"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"කාර්යාල පැතිකඩ වෙත මාරු වන්න"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"වසන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 7dc85b8..a646e5b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> %% dolnej hranice"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> %% ľavej hranice"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> %% pravej hranice"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Pracovné snímky obrazovky sú uložené v aplikácii <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žiadny zvuk ani vibrácie"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žiadny zvuk ani vibrácie a zobrazuje sa nižšie v sekcii konverzácií"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Môže zvoniť či vibrovať podľa nastavení telefónu"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Môže zvoniť alebo vibrovať podľa nastavení telefónu. Predvolene sa zobrazia konverzácie z bubliny <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Môže zvoniť či vibrovať podľa nastavení v zariadení"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Môže zvoniť alebo vibrovať podľa nastavení v zariadení. Predvolene sa zobrazia konverzácie z bubliny aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Nechajte systém určiť, či má toto upozornenie vydávať zvuk alebo vibrovať"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stav:</b> Preradené vyššie do kategórie Predvolené"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Preradené nižšie do kategórie Tiché"</string>
@@ -887,13 +885,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Späť"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ak tu chcete prehrávať obsah, priblížte zariadenie k zariadeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Načítava sa"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string>
@@ -917,8 +913,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hlasitosť"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a obrazovky"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Navrhované zariadenia"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"Vyžaduje prémiový účet"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ako vysielanie funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysielanie"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ľudia v okolí s kompatibilnými zariadeniami s rozhraním Bluetooth si môžu vypočuť médiá, ktoré vysielate"</string>
@@ -1060,8 +1056,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Táto obrazovka sa vypne"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozloženie skladacieho zariadenia"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Prevrátenie skladacieho zariadenia"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g> batérie"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pripojte dotykové pero k nabíjačke"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stav batérie dotykového pera je nízky"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Z tohto profilu nemôžete volať"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pracovné pravidlá vám umožňujú telefonovať iba v pracovnom profile"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prepnúť na pracovný profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavrieť"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 9d3c287..48c4a66 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Meja spodaj <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Meja levo <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Meja desno <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Posnetki zaslona v delovnem profilu so shranjeni v aplikaciji <xliff:g id="APP">%1$s</xliff:g>."</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Datoteke"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Samodejno"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Brez zvočnega opozarjanja ali vibriranja."</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brez zvočnega opozarjanja ali vibriranja, prikaz nižje v razdelku Pogovor."</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev telefona."</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev telefona. Pogovori v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> so privzeto prikazani v oblačkih."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Naj sistem določi, ali ob prejemu tega obvestila naprava predvaja zvok ali zavibrira"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stanje:</b> Uvrščeno med privzeta obvestila"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stanje:</b> Uvrščeno med obvestila brez zvoka"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednja"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Majhna"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Velika"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Končano"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavitve okna povečevalnika"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dotaknite se za funkcije za ljudi s posebnimi potrebami. Ta gumb lahko prilagodite ali zamenjate v nastavitvah.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Razveljavi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Če želite predvajati tukaj, se približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Nalaganje"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablični računalnik"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Glasnost"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvočniki in zasloni"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predlagane naprave"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Oddajanje"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ta zaslon se bo izklopil."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Razpiranje zložljive naprave"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Obračanje zložljive naprave"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostanek energije baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisalo s polnilnikom."</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 14438ef..0713019 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Kufiri i poshtëm <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kufiri i majtë <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Kufiri i djathtë <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Pamjet e ekranit të punës janë ruajtur në aplikacionin \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Skedarë"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatike"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Asnjë tingull ose dridhje"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Asnjë tingull ose dridhje dhe shfaqet më poshtë në seksionin e bisedave"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të telefonit"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të telefonit. Si parazgjedhje, bisedat nga <xliff:g id="APP_NAME">%1$s</xliff:g> shfaqen si flluska."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Kërkoji sistemit të përcaktojë nëse ky njoftim duhet të lëshojë tingull apo dridhje"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Statusi:</b> Promovuar si parazgjedhje"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statusi:</b> Ulur në nivel si në heshtje"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Zhbëj"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Afrohu për të luajtur në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Për ta luajtur këtu, afrohu më shumë te <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Ndodhi një gabim. Provo përsëri."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Po ngarkohet"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumi"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altoparlantët dhe ekranet"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Pajisjet e sugjeruara"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Si funksionon transmetimi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmetimi"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ky ekran do të fiket"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Pajisja e palosshme duke u hapur"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Pajisja e palosshme duke u rrotulluar"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Përqindja e mbetur e baterisë: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Lidhe stilolapsin me një karikues"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e724213..864b861 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Доња ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лева ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Десна ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Снимци екрана за посао се чувају у апликацији <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Фајлови"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Аутоматска"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука и вибрирања"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука и вибрирања и приказује се у наставку одељка за конверзације"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може да звони или вибрира у зависности од подешавања телефона"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може да звони или вибрира у зависности од подешавања телефона. Конверзације из апликације <xliff:g id="APP_NAME">%1$s</xliff:g> се подразумевано приказују у облачићима."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Нека систем утврди да ли ово обавештење треба да емитује звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> Унапређено у Подразумевано"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> Деградирано у Нечујно"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средње"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Мало"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Велико"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Измени"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Подешавања прозора за увећање"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Додирните за функције приступачности. Прилагодите или замените ово дугме у Подешавањима.\n\n"<annotation id="link">"Подешавања"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Опозови"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближите да бисте пуштали музику на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Да бисте пуштали садржај овде, приближите уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Дошло је до грешке. Пробајте поново."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Учитава се"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Звук"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени уређаји"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционише емитовање"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитовање"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Овај екран ће се искључити"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Уређај на преклоп се отвара"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Уређај на преклоп се обрће"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостало је још<xliff:g id="PERCENTAGE">%s</xliff:g> батерије"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Повежите писаљку са пуњачем"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Низак ниво батерије писаљке"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index eeee083..24c939c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatiskt"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Inga ljud eller vibrationer"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Inga ljud eller vibrationer och visas längre ned bland konversationerna"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringa eller vibrera beroende på inställningarna på telefonen"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringa eller vibrera beroende på inställningarna på telefonen. Konversationer från <xliff:g id="APP_NAME">%1$s</xliff:g> visas i bubblor som standard."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Låt systemet avgöra om den här aviseringen ska låta eller vibrera"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Ändrad till Standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Ändrad till Tyst"</string>
@@ -885,8 +887,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> från <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ångra"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytta närmare för att spela upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Kom närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela upp här"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Något gick fel. Försök igen."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Läser in"</string>
@@ -915,6 +916,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Högtalare och skärmar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Förslag på enheter"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Utsändning"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i närheten med kompatibla Bluetooth-enheter kan lyssna på medieinnehåll som du sänder ut"</string>
@@ -1056,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Den här skärmen inaktiveras"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> av batteriet återstår"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Anslut e-pennan till en laddare"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"E-pennans batterinivå är låg"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8e1067c..1c1d71e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Mpaka wa sehemu ya chini wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Mpaka wa sehemu ya kushoto wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Mpaka wa sehemu ya kulia wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Picha ya skrini ya kazi huhifadhiwa kwenye programu ya <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatiki"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Hakuna sauti wala mtetemo"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Hakuna sauti wala mtetemo na huonekana upande wa chini katika sehemu ya mazungumzo"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Huenda ikalia au kutetema kulingana na mipangilio ya simu"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Huenda ikalia au kutetema kulingana na mipangilio ya simu. Mazungumzo kutoka kiputo cha <xliff:g id="APP_NAME">%1$s</xliff:g> kwa chaguomsingi."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ruhusu mfumo ubainishe iwapo arifa hii inapaswa kutoa sauti au mtetemo"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Hali:</b> Imepandishwa Hadhi Kuwa Chaguomsingi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Imeshushwa Hadhi Kuwa Kimya"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> katika <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Tendua"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sogeza karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ili ucheze maudhui kwenye kifaa hiki, sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hitilafu fulani imetokea. Jaribu tena."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Inapakia"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"kompyuta kibao"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Sauti"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Spika na Skrini"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Vifaa Vilivyopendekezwa"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jinsi utangazaji unavyofanya kazi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Tangaza"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Skrini hii itajizima"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Chaji ya betri imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 2276e75..07f90ba 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"கீழ் எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"இடது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"வலது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"பணிக் கணக்கு ஸ்கிரீன்ஷாட்டுகள் <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸில் சேமிக்கப்படும்"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"தானியங்கு"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ஒலி / அதிர்வு இல்லை"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ஒலி / அதிர்வு இல்லாமல் உரையாடல் பிரிவின் கீழ்ப் பகுதியில் தோன்றும்"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"மொபைல் அமைப்புகளின் அடிப்படையில் ஒலிக்கலாம்/அதிரலாம்"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"மொபைல் அமைப்புகளின் அடிப்படையில் ஒலிக்கவோ அதிரவோ செய்யும். <xliff:g id="APP_NAME">%1$s</xliff:g> இலிருந்து வரும் உரையாடல்கள் இயல்பாகவே குமிழாகத் தோன்றும்."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"இந்த அறிவிப்பு ஒலி எழுப்ப வேண்டுமா அதிர வேண்டுமா என்பதை சிஸ்டம் தீர்மானிக்கும்"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>நிலை:</b> இயல்புநிலைக்கு உயர்த்தி அமைக்கப்பட்டது"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>நிலை:</b> சைலன்ட் நிலைக்குக் குறைத்து அமைக்கப்பட்டது"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%2$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"செயல்தவிர்"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் இயக்க உங்கள் சாதனத்தை அருகில் எடுத்துச் செல்லுங்கள்"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g>அருகில் நகர்த்துங்கள்"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"ஏற்றுகிறது"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"டேப்லெட்"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ஒலியளவு"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ஸ்பீக்கர்கள் & டிஸ்ப்ளேக்கள்"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"பரிந்துரைக்கப்படும் சாதனங்கள்"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"பிராட்காஸ்ட்"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ இந்தத் திரை ஆஃப் ஆகிவிடும்"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> பேட்டரி மீதமுள்ளது"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"உங்கள் ஸ்டைலஸைச் சார்ஜருடன் இணையுங்கள்"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a749277..824fd11 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ఆటోమేటిక్"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"శబ్దం లేదా వైబ్రేషన్లు ఏవీ లేవు"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"శబ్దం లేదా వైబ్రేషన్ లేదు, సంభాషణ విభాగం దిగువన కనిపిస్తుంది"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"ఫోన్ సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ఫోన్ సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు. <xliff:g id="APP_NAME">%1$s</xliff:g> నుండి సంభాషణలు ఆటోమేటిక్గా బబుల్గా కనిపిస్తాయి."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"పరికర సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"పరికర సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు. <xliff:g id="APP_NAME">%1$s</xliff:g> నుండి సంభాషణలు ఆటోమేటిక్గా బబుల్లో కనిపిస్తాయి."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ఈ నోటిఫికేషన్ వచ్చినప్పుడు శబ్దం చేయాలా లేదా వైబ్రేట్ చేయాలా అనేది నిర్ణయించడానికి సిస్టమ్కు అనుమతి ఇవ్వండి"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>స్టేటస్:</b> ఆటోమేటిక్ సెట్టింగ్కు ప్రోమోట్ చేయబడింది"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>స్టేటస్:</b> నిశ్శబ్దం స్థాయికి తగ్గించబడింది"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"మధ్యస్థం"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"చిన్నది"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"పెద్దది"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"పూర్తయింది"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ఎడిట్ చేయండి"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"మాగ్నిఫయర్ విండో సెట్టింగ్లు"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్లలో ఈ బటన్ను అనుకూలంగా మార్చండి లేదా రీప్లేస్ చేయండి.\n\n"<annotation id="link">"వీక్షణ సెట్టింగ్లు"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> నుండి <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"చర్య రద్దు"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే చేయడానికి దగ్గరగా వెళ్లండి"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ఇక్కడ ఆడటానికి, <xliff:g id="DEVICENAME">%1$s</xliff:g>కు దగ్గరగా వెళ్లండి"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"లోడ్ అవుతోంది"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"స్పీకర్లు & డిస్ప్లేలు"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"సూచించబడిన పరికరాలు"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"ప్రీమియం ఖాతా అవసరం"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ప్రసారం"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"మీకు సమీపంలో ఉన్న వ్యక్తులు అనుకూలత ఉన్న బ్లూటూత్ పరికరాలతో మీరు ప్రసారం చేస్తున్న మీడియాను వినగలరు"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ఈ స్క్రీన్ ఆఫ్ అవుతుంది"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> బ్యాటరీ మిగిలి ఉంది"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"మీ స్టైలస్ను ఛార్జర్కి కనెక్ట్ చేయండి"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"తక్కువ స్టైలస్ బ్యాటరీ"</string>
+ <string name="video_camera" msgid="7654002575156149298">"వీడియో కెమెరా"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ఈ ప్రొఫైల్ నుండి కాల్ చేయడం సాధ్యపడలేదు"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"మీ వర్క్ పాలసీ, మిమ్మల్ని వర్క్ ప్రొఫైల్ నుండి మాత్రమే ఫోన్ కాల్స్ చేయడానికి అనుమతిస్తుంది"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"వర్క్ ప్రొఫైల్కు మారండి"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"మూసివేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e72471b..ff1bf35 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"อัตโนมัติ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ไม่มีเสียงหรือการสั่น"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ไม่มีเสียงหรือการสั่น และปรากฏต่ำลงมาในส่วนการสนทนา"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์ การสนทนาจาก <xliff:g id="APP_NAME">%1$s</xliff:g> จะแสดงเป็นบับเบิลโดยค่าเริ่มต้น"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าอุปกรณ์"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าอุปกรณ์ การสนทนาจาก <xliff:g id="APP_NAME">%1$s</xliff:g> จะแสดงเป็นบับเบิลโดยค่าเริ่มต้น"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ให้ระบบพิจารณาว่าจะให้การแจ้งเตือนนี้ส่งเสียงหรือสั่นหรือไม่"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>สถานะ:</b> เลื่อนระดับเป็นค่าเริ่มต้น"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>สถานะ:</b> ลดระดับเป็นปิดเสียง"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"ปานกลาง"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"เล็ก"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"ใหญ่"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"เสร็จสิ้น"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"แก้ไข"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"การตั้งค่าหน้าต่างแว่นขยาย"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"แตะเพื่อเปิดฟีเจอร์การช่วยเหลือพิเศษ ปรับแต่งหรือแทนที่ปุ่มนี้ในการตั้งค่า\n\n"<annotation id="link">"ดูการตั้งค่า"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> จาก <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"เลิกทำ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ขยับไปใกล้มากขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"กำลังโหลด"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ลำโพงและจอแสดงผล"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"อุปกรณ์ที่แนะนำ"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"ต้องใช้บัญชี Premium"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ประกาศ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ผู้ที่อยู่ใกล้คุณและมีอุปกรณ์บลูทูธที่รองรับสามารถรับฟังสื่อที่คุณกำลังออกอากาศได้"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ หน้าจอนี้จะปิดไป"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"อุปกรณ์ที่พับได้กำลังกางออก"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"อุปกรณ์ที่พับได้กำลังพลิกไปมา"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"เหลือแบตเตอรี่ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"เชื่อมต่อสไตลัสกับที่ชาร์จ"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"แบตเตอรี่สไตลัสเหลือน้อย"</string>
+ <string name="video_camera" msgid="7654002575156149298">"กล้องวิดีโอ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"โทรจากโปรไฟล์นี้ไม่ได้"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"นโยบายการทำงานอนุญาตให้คุณโทรออกได้จากโปรไฟล์งานเท่านั้น"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d8f5bad..a287d20 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Awtomatiko"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Walang tunog o pag-vibrate"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Walang tunog o pag-vibrate at lumalabas nang mas mababa sa seksyon ng pag-uusap"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng telepono"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng telepono. Mga pag-uusap mula sa <xliff:g id="APP_NAME">%1$s</xliff:g> bubble bilang default."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ipatukoy sa system kung dapat gumawa ng tunog o pag-vibrate ang notification na ito"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Na-promote sa Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Na-demote sa Naka-silent"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Katamtaman"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Maliit"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Malaki"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Tapos na"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"I-edit"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Mga setting ng window ng magnifier"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"I-tap, buksan mga feature ng accessibility. I-customize o palitan button sa Mga Setting.\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
@@ -885,8 +886,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"I-undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Lumapit pa para mag-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Para mag-play dito, lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nagkaproblema. Subukan ulit."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Naglo-load"</string>
@@ -915,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Mga Speaker at Display"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Mga Iminumungkahing Device"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Makakapakinig ang mga taong malapit sa iyo na may mga compatible na Bluetooth device sa media na bino-broadcast mo"</string>
@@ -1056,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Mag-o-off ang screen na ito"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterya na lang ang natitira"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ikonekta sa charger ang iyong stylus"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Paubos na ang baterya ng stylus"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 52088dbb..de21f2c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alt sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sol sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sağ sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"İş profilindeki ekran görüntüleri <xliff:g id="APP">%1$s</xliff:g> uygulamasına kaydedilir"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dosyalar"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sessiz veya titreşim yok"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ses veya titreşim yok, görüşme bölümünün altında görünür"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir <xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamadan görüşmeler varsayılan olarak baloncukla gösterilir."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirimin ses çıkarması veya titreşmesi gerekip gerekmediğine sistem karar versin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Durum:</b> Varsayılana yükseltildi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Durum:</b> Sessize Düşürüldü"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> uygulamasından <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Geri al"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatmak için yaklaşın"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string>
- <string name="media_transfer_failed" msgid="7955354964610603723">"Bir sorun oldu. Tekrar deneyin."</string>
+ <string name="media_transfer_failed" msgid="7955354964610603723">"Bir hata oluştu. Tekrar deneyin."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Yükleme"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ses düzeyi"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hoparlörler ve Ekranlar"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Önerilen Cihazlar"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Anons"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ * Bu ekran kapatılacak"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> pil kaldı"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ekran kaleminizi bir şarj cihazına bağlayın"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9638c65..61fc89c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Знизу на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Зліва на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Справа на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Робочі знімки екрана зберігаються в додатку <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файли"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запис відео з екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звуку чи вібрації"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звуку чи вібрації, з\'являється нижче в розділі розмов"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Дзвінок або вібрація залежно від налаштувань телефона"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Дзвінок або вібрація залежно від налаштувань телефона. Розмови з додатка <xliff:g id="APP_NAME">%1$s</xliff:g> за умовчанням з\'являються як спливаючий чат."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволити системі визначати, чи має сповіщення супроводжуватися звуком або вібрацією"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус</b>: підвищено до \"За умовчанням\""</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус</b>: знижено до \"Без звуку\""</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" у додатку <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Відмінити"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Щоб відтворити контент на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>, наблизьтеся до нього"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Щоб відтворити на цьому пристрої, перемістіть його ближче до пристрою \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Сталася помилка. Повторіть спробу."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Завантаження"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучність"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки й екрани"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Пропоновані пристрої"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляція"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Цей екран вимкнеться"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Заряд акумулятора: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Підключіть стилус до зарядного пристрою"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 46acc98..bec50f1 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"نیچے کا احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"بایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"دایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"دفتری اسکرین شاٹس کو <xliff:g id="APP">%1$s</xliff:g> ایپ میں محفوظ کیا جاتا ہے"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"فائلز"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"اسکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
@@ -545,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"کوئی آواز یا وائبریشن نہیں"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"کوئی آواز یا وائبریشن نہیں اور گفتگو کے سیکشن میں نیچے ظاہر ہوتا ہے"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"آپ کے آلہ کی ترتیبات کے مطابق وائبریٹ یا گھنٹی بج سکتی ہے"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"فون کی ترتیبات کے مطابق وائبریٹ یا گھنٹی بج سکتی ہے۔ بذریعہ ڈیفالٹ <xliff:g id="APP_NAME">%1$s</xliff:g> بلبلہ سے گفتگوئیں۔"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"آلے کی ترتیبات کی بنیاد پر وائبریٹ یا گھنٹی بج سکتی ہے"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"آلے کی ترتیبات بنیاد پر وائبریٹ یا گھنٹی بج سکتی ہے۔ بذریعہ ڈیفالٹ <xliff:g id="APP_NAME">%1$s</xliff:g> بلبلہ سے گفتگوئیں۔"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"سسٹم کو اس بات کا تعین کرنے دیں کہ آیا اس اطلاع کی آواز ہو یا وائبریٹ ہونا چاہیے"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> ڈیفالٹ پر درجہ بند کیا گیا"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>اسٹیٹس:</b> کو خاموش پر درجہ بند کیا گیا"</string>
@@ -814,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"متوسط"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"چھوٹا"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"بڑا"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"ہو گیا"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ترمیم کریں"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"میگنیفائر ونڈو کی ترتیبات"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ایکسیسبیلٹی خصوصیات کھولنے کے لیے تھپتھپائیں۔ ترتیبات میں اس بٹن کو حسب ضرورت بنائیں یا تبدیل کریں۔\n\n"<annotation id="link">"ترتیبات ملاحظہ کریں"</annotation></string>
@@ -887,13 +884,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> سے <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"کالعدم کریں"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"یہاں چلانے کے لیے، <xliff:g id="DEVICENAME">%1$s</xliff:g> کے زیادہ جائیں"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"کچھ غلط ہوگیا۔ پھر کوشش کریں۔"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"لوڈ ہو رہا ہے"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ٹیبلیٹ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
@@ -917,8 +912,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"والیوم"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"اسپیکرز اور ڈسپلیز"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
- <skip />
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"تجویز کردہ آلات"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"پریمئیم اکاؤنٹ درکار ہے"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"براڈکاسٹنگ کیسے کام کرتا ہے"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"براڈکاسٹ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"موافق بلوٹوتھ آلات کے ساتھ آپ کے قریبی لوگ آپ کے نشر کردہ میڈیا کو سن سکتے ہیں"</string>
@@ -1062,4 +1057,10 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"فولڈ ہونے والے آلے کو گھمایا جا رہا ہے"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> بیٹری باقی ہے"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"اپنے اسٹائلس کو چارجر منسلک کریں"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"اسٹائلس بیٹری کم ہے"</string>
+ <string name="video_camera" msgid="7654002575156149298">"ویڈیو کیمرا"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"اس پروفائل سے کال نہیں کر سکتے"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"آپ کے کام سے متعلق پالیسی آپ کو صرف دفتری پروفائل سے فون کالز کرنے کی اجازت دیتی ہے"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"دفتری پروفائل پر سوئچ کریں"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"بند کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index ef7dbad..939cb5c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -543,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tovush yoki tebranishsiz"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tovush yoki tebranishsiz hamda suhbatlar ruknining pastida chiqadi"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon sozlamalari asosida jiringlashi yoki tebranishi mumkin"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon sozlamalari asosida jiringlashi yoki tebranishi mumkin. <xliff:g id="APP_NAME">%1$s</xliff:g> suhbatlari standart holatda bulutcha shaklida chiqadi."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirishnoma jiringlashi yoki tebranishini hal qilsin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Holati:</b> Birlamchi darajaga chiqarildi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Holati:</b> Sokin darajaga tushirildi"</string>
@@ -812,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Oʻrtacha"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Kichik"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Yirik"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Tayyor"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Tahrirlash"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Lupa oynasi sozlamalari"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Maxsus imkoniyatlarni ochish uchun bosing Sozlamalardan moslay yoki almashtira olasiz.\n\n"<annotation id="link">"Sozlamalar"</annotation></string>
@@ -914,6 +915,8 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Karnaylar va displeylar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Taklif qilingan qurilmalar"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Translatsiya qanday ishlaydi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Translatsiya"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Atrofingizdagi mos Bluetooth qurilmasiga ega foydalanuvchilar siz translatsiya qilayotgan mediani tinglay olishadi"</string>
@@ -1057,4 +1060,15 @@
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string>
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batareya quvvati: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Stilusni quvvat manbaiga ulang"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus batareyasi kam"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4ba82a1..2326813 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Cạnh dưới cùng <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Cạnh trái <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Cạnh phải <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Ảnh chụp màn hình công việc được lưu trong ứng dụng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Tự động"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Không phát âm thanh hoặc rung"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Có thể đổ chuông hoặc rung tùy theo chế độ cài đặt trên điện thoại"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Có thể đổ chuông hoặc rung tùy theo chế độ cài đặt trên điện thoại. Các cuộc trò chuyện từ <xliff:g id="APP_NAME">%1$s</xliff:g> sẽ hiện ở dạng bong bóng theo mặc định."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Cho phép hệ thống quyết định xem thông báo này phát âm thanh hay rung"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Trạng thái:</b> Đã thay đổi thành Mặc định"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Trạng thái:</b> Đã thay đổi thành Im lặng"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Vừa"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Nhỏ"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Lớn"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Xong"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Chỉnh sửa"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Chế độ cài đặt cửa sổ phóng to"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Nhấn để mở bộ tính năng hỗ trợ tiếp cận. Tuỳ chỉnh/thay thế nút này trong phần Cài đặt.\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> trên <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Hủy"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Đưa thiết bị đến gần hơn để phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Để phát ở đây, vui lòng lại gần <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Đã xảy ra lỗi. Hãy thử lại."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Đang tải"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"máy tính bảng"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Âm lượng"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Loa và màn hình"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Thiết bị được đề xuất"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Truyền"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Màn hình này sẽ tắt"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Còn <xliff:g id="PERCENTAGE">%s</xliff:g> pin"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hãy kết nối bút cảm ứng với bộ sạc"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4426839..bfc6cc5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"底部边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"工作屏幕截图保存在“<xliff:g id="APP">%1$s</xliff:g>”应用中"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"文件"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自动"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音,也不振动"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"可能会响铃或振动(取决于手机设置)"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能会响铃或振动(取决于手机设置)。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以对话泡的形式显示。"</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"让系统决定是否应让设备在收到此通知时发出提示音或振动"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>状态</b>:已提升为“默认”"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>状态</b>:已降低为“静音”"</string>
@@ -887,13 +887,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"通过<xliff:g id="APP_LABEL">%2$s</xliff:g>播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"撤消"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"若要在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放,请靠近这台设备"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"若要在此设备上播放,请再靠近<xliff:g id="DEVICENAME">%1$s</xliff:g>一点"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"出了点问题,请重试。"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"正在加载"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板电脑"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
@@ -917,7 +915,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"音箱和显示屏"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建议的设备"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"广播"</string>
@@ -1060,8 +1059,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 此屏幕将会关闭"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"电池还剩 <xliff:g id="PERCENTAGE">%s</xliff:g> 的电量"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"请将触控笔连接充电器"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 04a06bc..3f14f5e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"無音效或震動"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"無音效或震動,並在對話部分的較低位置顯示"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"根據手機設定發出鈴聲或震動"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能會根據手機設定發出鈴聲或震動。「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會預設以對話氣泡顯示。"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"根據裝置的設定響鈴或震動"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"根據裝置的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"由系統判斷是否要讓此通知發出音效或震動"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>狀態:</b>已提升為預設"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>狀態:</b>已降低為靜音"</string>
@@ -812,15 +812,14 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"完成"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編輯"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"㩒一下就可以開無障礙功能。喺「設定」度自訂或者取代呢個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣即可暫時隱藏"</string>
<string name="accessibility_floating_button_undo" msgid="511112888715708241">"復原"</string>
- <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"已移除「<xliff:g id="FEATURE_NAME">%s</xliff:g>」捷徑"</string>
- <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{已移除 # 個捷徑}other{已移除 # 個捷徑}}"</string>
+ <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"已移除「<xliff:g id="FEATURE_NAME">%s</xliff:g>」快速鍵"</string>
+ <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{已移除 # 個快速鍵}other{已移除 # 個快速鍵}}"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移去左上方"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移去右上方"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移到左下方"</string>
@@ -885,11 +884,10 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"在 <xliff:g id="APP_LABEL">%2$s</xliff:g> 播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"如要在這部裝置播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」一點"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
- <string name="media_transfer_loading" msgid="5544017127027152422">"載入中"</string>
+ <string name="media_transfer_loading" msgid="5544017127027152422">"正在載入"</string>
<string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板電腦"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"必須有付費帳戶"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近有兼容藍牙裝置的人可收聽您正在廣播的媒體內容"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 此螢幕將關閉"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"剩餘電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆連接充電器"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string>
+ <string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"無法透過這個資料夾撥打電話"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"貴公司政策僅允許透過工作資料夾撥打電話"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作資料夾"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1df1cfb..e02597f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -543,8 +543,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不震動或發出聲音"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不震動或發出聲音,並顯示在對話區的下方"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"根據手機的設定響鈴或震動"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能會根據手機的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"根據裝置的設定響鈴或震動"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"根據裝置的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"由系統判斷要讓裝置在收到這則通知時震動還是發出音效"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>狀態:</b>已提升為預設"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>狀態:</b>已降低為靜音"</string>
@@ -812,8 +812,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"完成"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編輯"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"輕觸即可開啟無障礙功能。你可以前往「設定」自訂或更換這個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
@@ -885,8 +884,7 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"透過「<xliff:g id="APP_LABEL">%2$s</xliff:g>」播放〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"如要在這部裝置播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"載入中"</string>
@@ -915,6 +913,7 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
+ <string name="media_output_status_require_premium" msgid="5691200962588753380">"必須有付費帳戶"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"如果附近的人有相容的藍牙裝置,就可以聽到你正在廣播的媒體內容"</string>
@@ -1056,8 +1055,12 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 這麼做會關閉這個螢幕"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
- <skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"剩餘電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆接上充電器"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電力不足"</string>
+ <string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"無法透過這個資料夾撥打電話"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"貴公司政策僅允許透過工作資料夾撥打電話"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作資料夾"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a0153b3..a68b214 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -91,10 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ophansi"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ongakwesobunxele"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ongakwesokudla"</string>
- <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
- <skip />
- <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
- <skip />
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Izithombe-skrini zomsebenzi zigcinwa ku-app ye-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Amafayela"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
@@ -545,8 +543,10 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Okuzenzekelayo"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Awukho umsindo noma ukudlidliza"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Awukho umsindo noma ukudlidliza futhi ivela ngezansi esigabeni sengxoxo"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Ingase ikhale noma idlidlize kuya ngamasethingi wefoni yakho"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Ingase ikhale noma idlidlize kuya ngamasethingi wefoni yakho. Izingxoxo ezivela ku-<xliff:g id="APP_NAME">%1$s</xliff:g> ziba yibhamuza ngokuzenzakalela."</string>
+ <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
+ <skip />
+ <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
+ <skip />
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Vumela isistimu inqume uma lesi saziso kufanele senze umsindo noma sidlidlize"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Isimo:</b> Siphromothelwe Kokuzenzakalelayo"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Isimo:</b> Sehliselwe Kokuthulile"</string>
@@ -814,8 +814,7 @@
<string name="accessibility_magnification_medium" msgid="6994632616884562625">"Kumaphakathi"</string>
<string name="accessibility_magnification_small" msgid="8144502090651099970">"Esincane"</string>
<string name="accessibility_magnification_large" msgid="6602944330021308774">"Obukhulu"</string>
- <!-- no translation found for accessibility_magnification_done (263349129937348512) -->
- <skip />
+ <string name="accessibility_magnification_done" msgid="263349129937348512">"Kwenziwe"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Hlela"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Amasethingi ewindi lesikhulisi"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Thepha ukuze uvule izakhi zokufinyelela. Enza ngendlela oyifisayo noma shintsha le nkinobho Kumasethingi.\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
@@ -887,13 +886,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Hlehlisa"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sondeza eduze ukudlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
- <skip />
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Ukuze udlale lapha, sondela ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Iyalayisha"</string>
- <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
- <skip />
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ithebulethi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
@@ -917,7 +914,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ivolumu"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Izipikha Neziboniso"</string>
- <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Amadivayisi Aphakanyisiwe"</string>
+ <!-- no translation found for media_output_status_require_premium (5691200962588753380) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Sakaza"</string>
@@ -1060,8 +1058,17 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Lesi sikrini sizovala"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string>
- <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ibhethri elisele"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Xhuma i-stylus yakho kushaja"</string>
+ <string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string>
+ <!-- no translation found for video_camera (7654002575156149298) -->
<skip />
- <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
+ <skip />
+ <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6202939..f122805 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1087,6 +1087,7 @@
(112 - 40) / 2 = 36dp -->
<dimen name="media_ttt_generic_icon_padding">36dp</dimen>
<dimen name="media_ttt_receiver_vert_translation">40dp</dimen>
+ <dimen name="media_ttt_receiver_icon_bottom_margin">10dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index c5ffc94..6354752 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -33,8 +33,6 @@
<!-- Whether to show chipbar UI whenever the device is unlocked by ActiveUnlock. -->
<bool name="flag_active_unlock_chipbar">true</bool>
- <bool name="flag_smartspace">false</bool>
-
<!-- Whether the user switcher chip shows in the status bar. When true, the multi user
avatar will no longer show on the lockscreen -->
<bool name="flag_user_switcher_chip">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3d3bb6e..31aeff4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2342,6 +2342,14 @@
<!-- Removed control in management screen [CHAR LIMIT=20] -->
<string name="controls_removed">Removed</string>
+ <!-- Title for the dialog presented to the user to authorize this app to display a Device
+ controls panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=30] -->
+ <string name="controls_panel_authorization_title">Add <xliff:g id="appName" example="My app">%s</xliff:g>?</string>
+
+ <!-- Shows in a dialog presented to the user to authorize this app to display a Device controls
+ panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] -->
+ <string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string>
+
<!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
<string name="accessibility_control_favorite">Favorited</string>
<!-- a11y state description for a control that is currently favorited with its position [CHAR LIMIT=NONE] -->
@@ -2491,6 +2499,8 @@
<string name="controls_menu_add">Add controls</string>
<!-- Controls menu, edit [CHAR_LIMIT=30] -->
<string name="controls_menu_edit">Edit controls</string>
+ <!-- Controls menu, add another app [CHAR LIMIT=30] -->
+ <string name="controls_menu_add_another_app">Add app</string>
<!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
<string name="media_output_dialog_add_output">Add outputs</string>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 8a0fca0..28e786b 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -91,6 +91,9 @@
static_libs: [
"SystemUI-flag-types",
],
+ optimize: {
+ proguard_flags_files: ["proguard_flags.flags"],
+ },
java_version: "1.8",
min_sdk_version: "current",
}
diff --git a/packages/SystemUI/shared/proguard_flags.flags b/packages/SystemUI/shared/proguard_flags.flags
new file mode 100644
index 0000000..08859cd
--- /dev/null
+++ b/packages/SystemUI/shared/proguard_flags.flags
@@ -0,0 +1 @@
+-keep class * implements com.android.systemui.flags.ParcelableFlag
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index fa484c7..a71fb56 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -37,7 +37,7 @@
/**
* Sent when overview is to be shown.
*/
- void onOverviewShown(boolean triggeredFromAltTab, boolean forward) = 7;
+ void onOverviewShown(boolean triggeredFromAltTab) = 7;
/**
* Sent when overview is to be hidden.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index 0ee813b..ef2247f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -15,39 +15,36 @@
*/
package com.android.systemui.shared.regionsampling
+import android.app.WallpaperColors
+import android.app.WallpaperManager
import android.graphics.Color
+import android.graphics.Point
import android.graphics.Rect
+import android.graphics.RectF
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.shared.navigationbar.RegionSamplingHelper
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper.SamplingCallback
import java.io.PrintWriter
import java.util.concurrent.Executor
/** Class for instance of RegionSamplingHelper */
-open class RegionSampler(
- sampledView: View?,
+open class RegionSampler
+@JvmOverloads
+constructor(
+ val sampledView: View?,
mainExecutor: Executor?,
- bgExecutor: Executor?,
- regionSamplingEnabled: Boolean,
- updateFun: UpdateColorCallback
-) {
+ val bgExecutor: Executor?,
+ val regionSamplingEnabled: Boolean,
+ val updateForegroundColor: UpdateColorCallback,
+ val wallpaperManager: WallpaperManager? = WallpaperManager.getInstance(sampledView?.context)
+) : WallpaperManager.LocalWallpaperColorConsumer {
private var regionDarkness = RegionDarkness.DEFAULT
private var samplingBounds = Rect()
private val tmpScreenLocation = IntArray(2)
@VisibleForTesting var regionSampler: RegionSamplingHelper? = null
private var lightForegroundColor = Color.WHITE
private var darkForegroundColor = Color.BLACK
-
- @VisibleForTesting
- open fun createRegionSamplingHelper(
- sampledView: View,
- callback: SamplingCallback,
- mainExecutor: Executor?,
- bgExecutor: Executor?
- ): RegionSamplingHelper {
- return RegionSamplingHelper(sampledView, callback, mainExecutor, bgExecutor)
- }
+ private val displaySize = Point()
/**
* Sets the colors to be used for Dark and Light Foreground.
@@ -73,7 +70,7 @@
}
}
- private fun convertToClockDarkness(isRegionDark: Boolean): RegionDarkness {
+ private fun getRegionDarkness(isRegionDark: Boolean): RegionDarkness {
return if (isRegionDark) {
RegionDarkness.DARK
} else {
@@ -87,12 +84,32 @@
/** Start region sampler */
fun startRegionSampler() {
- regionSampler?.start(samplingBounds)
+ if (!regionSamplingEnabled || sampledView == null) {
+ return
+ }
+
+ val sampledRegion = calculateSampledRegion(sampledView)
+ val regions = ArrayList<RectF>()
+ val sampledRegionWithOffset = convertBounds(sampledRegion)
+ regions.add(sampledRegionWithOffset)
+
+ wallpaperManager?.removeOnColorsChangedListener(this)
+ wallpaperManager?.addOnColorsChangedListener(this, regions)
+
+ // TODO(b/265969235): conditionally set FLAG_LOCK or FLAG_SYSTEM once HS smartspace
+ // implemented
+ bgExecutor?.execute(
+ Runnable {
+ val initialSampling =
+ wallpaperManager?.getWallpaperColors(WallpaperManager.FLAG_LOCK)
+ onColorsChanged(sampledRegionWithOffset, initialSampling)
+ }
+ )
}
/** Stop region sampler */
fun stopRegionSampler() {
- regionSampler?.stop()
+ wallpaperManager?.removeOnColorsChangedListener(this)
}
/** Dump region sampler */
@@ -100,43 +117,66 @@
regionSampler?.dump(pw)
}
- init {
- if (regionSamplingEnabled && sampledView != null) {
- regionSampler =
- createRegionSamplingHelper(
- sampledView,
- object : SamplingCallback {
- override fun onRegionDarknessChanged(isRegionDark: Boolean) {
- regionDarkness = convertToClockDarkness(isRegionDark)
- updateFun()
- }
- /**
- * The method getLocationOnScreen is used to obtain the view coordinates
- * relative to its left and top edges on the device screen. Directly
- * accessing the X and Y coordinates of the view returns the location
- * relative to its parent view instead.
- */
- override fun getSampledRegion(sampledView: View): Rect {
- val screenLocation = tmpScreenLocation
- sampledView.getLocationOnScreen(screenLocation)
- val left = screenLocation[0]
- val top = screenLocation[1]
- samplingBounds.left = left
- samplingBounds.top = top
- samplingBounds.right = left + sampledView.width
- samplingBounds.bottom = top + sampledView.height
- return samplingBounds
- }
+ fun calculateSampledRegion(sampledView: View): RectF {
+ val screenLocation = tmpScreenLocation
+ /**
+ * The method getLocationOnScreen is used to obtain the view coordinates relative to its
+ * left and top edges on the device screen. Directly accessing the X and Y coordinates of
+ * the view returns the location relative to its parent view instead.
+ */
+ sampledView.getLocationOnScreen(screenLocation)
+ val left = screenLocation[0]
+ val top = screenLocation[1]
- override fun isSamplingEnabled(): Boolean {
- return regionSamplingEnabled
- }
- },
- mainExecutor,
- bgExecutor
- )
- }
- regionSampler?.setWindowVisible(true)
+ samplingBounds.left = left
+ samplingBounds.top = top
+ samplingBounds.right = left + sampledView.width
+ samplingBounds.bottom = top + sampledView.height
+
+ return RectF(samplingBounds)
+ }
+
+ /**
+ * Convert the bounds of the region we want to sample from to fractional offsets because
+ * WallpaperManager requires the bounds to be between [0,1]. The wallpaper is treated as one
+ * continuous image, so if there are multiple screens, then each screen falls into a fractional
+ * range. For instance, 4 screens have the ranges [0, 0.25], [0,25, 0.5], [0.5, 0.75], [0.75,
+ * 1].
+ */
+ fun convertBounds(originalBounds: RectF): RectF {
+
+ // TODO(b/265969235): GRAB # PAGES + CURRENT WALLPAPER PAGE # FROM LAUNCHER
+ // TODO(b/265968912): remove hard-coded value once LS wallpaper supported
+ val wallpaperPageNum = 0
+ val numScreens = 1
+
+ val screenWidth = displaySize.x
+ // TODO: investigate small difference between this and the height reported in go/web-hv
+ val screenHeight = displaySize.y
+
+ val newBounds = RectF()
+ // horizontal
+ newBounds.left = ((originalBounds.left / screenWidth) + wallpaperPageNum) / numScreens
+ newBounds.right = ((originalBounds.right / screenWidth) + wallpaperPageNum) / numScreens
+ // vertical
+ newBounds.top = originalBounds.top / screenHeight
+ newBounds.bottom = originalBounds.bottom / screenHeight
+
+ return newBounds
+ }
+
+ init {
+ sampledView?.context?.display?.getSize(displaySize)
+ }
+
+ override fun onColorsChanged(area: RectF?, colors: WallpaperColors?) {
+ // update text color when wallpaper color changes
+ regionDarkness =
+ getRegionDarkness(
+ (colors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) !=
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT
+ )
+ updateForegroundColor()
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 766266d..0d35aa3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -112,7 +112,8 @@
public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25;
// Freeform windows are showing in desktop mode
public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
-
+ // Device dreaming state
+ public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -141,7 +142,8 @@
SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
SYSUI_STATE_IMMERSIVE_MODE,
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
- SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
+ SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
+ SYSUI_STATE_DEVICE_DREAMING
})
public @interface SystemUiStateFlags {}
@@ -179,6 +181,8 @@
str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : "");
str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
? "freeform_active_in_desktop_mode" : "");
+ str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
+
return str.toString();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index a45ce42..1680b47 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -24,6 +24,7 @@
import android.text.format.DateFormat
import android.util.TypedValue
import android.view.View
+import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -47,18 +48,17 @@
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import com.android.systemui.statusbar.policy.ConfigurationController
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.launch
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.Executor
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.launch
/**
* Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
@@ -89,7 +89,11 @@
value.largeClock.logBuffer = largeLogBuffer
value.initialize(resources, dozeAmount, 0f)
- updateRegionSamplers(value)
+
+ if (regionSamplingEnabled) {
+ clock?.smallClock?.view?.addOnLayoutChangeListener(mLayoutChangedListener)
+ clock?.largeClock?.view?.addOnLayoutChangeListener(mLayoutChangedListener)
+ }
updateFontSizes()
}
}
@@ -104,47 +108,87 @@
private var disposableHandle: DisposableHandle? = null
private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING)
- private fun updateColors() {
+ private val mLayoutChangedListener = object : View.OnLayoutChangeListener {
+ private var currentSmallClockView: View? = null
+ private var currentLargeClockView: View? = null
+ private var currentSmallClockLocation = IntArray(2)
+ private var currentLargeClockLocation = IntArray(2)
- if (regionSamplingEnabled && smallRegionSampler != null && largeRegionSampler != null) {
- val wallpaperManager = WallpaperManager.getInstance(context)
- if (!wallpaperManager.lockScreenWallpaperExists()) {
- smallClockIsDark = smallRegionSampler!!.currentRegionDarkness().isDark
- largeClockIsDark = largeRegionSampler!!.currentRegionDarkness().isDark
- }
- } else {
- val isLightTheme = TypedValue()
- context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
- smallClockIsDark = isLightTheme.data == 0
- largeClockIsDark = isLightTheme.data == 0
+ override fun onLayoutChange(
+ view: View?,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ val parent = (view?.parent) as FrameLayout
+
+ // don't pass in negative bounds when clocks are in transition state
+ if (view.locationOnScreen[0] < 0 || view.locationOnScreen[1] < 0) {
+ return
}
+ // SMALL CLOCK
+ if (parent.id == R.id.lockscreen_clock_view) {
+ // view bounds have changed due to clock size changing (i.e. different character widths)
+ // AND/OR the view has been translated when transitioning between small and large clock
+ if (view != currentSmallClockView ||
+ !view.locationOnScreen.contentEquals(currentSmallClockLocation)) {
+ currentSmallClockView = view
+ currentSmallClockLocation = view.locationOnScreen
+ updateRegionSampler(view)
+ }
+ }
+ // LARGE CLOCK
+ else if (parent.id == R.id.lockscreen_clock_view_large) {
+ if (view != currentLargeClockView ||
+ !view.locationOnScreen.contentEquals(currentLargeClockLocation)) {
+ currentLargeClockView = view
+ currentLargeClockLocation = view.locationOnScreen
+ updateRegionSampler(view)
+ }
+ }
+ }
+ }
+
+ private fun updateColors() {
+ val wallpaperManager = WallpaperManager.getInstance(context)
+ if (regionSamplingEnabled && !wallpaperManager.lockScreenWallpaperExists()) {
+ if (regionSampler != null) {
+ if (regionSampler?.sampledView == clock?.smallClock?.view) {
+ smallClockIsDark = regionSampler!!.currentRegionDarkness().isDark
+ clock?.smallClock?.events?.onRegionDarknessChanged(smallClockIsDark)
+ return
+ } else if (regionSampler?.sampledView == clock?.largeClock?.view) {
+ largeClockIsDark = regionSampler!!.currentRegionDarkness().isDark
+ clock?.largeClock?.events?.onRegionDarknessChanged(largeClockIsDark)
+ return
+ }
+ }
+ }
+
+ val isLightTheme = TypedValue()
+ context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
+ smallClockIsDark = isLightTheme.data == 0
+ largeClockIsDark = isLightTheme.data == 0
+
clock?.smallClock?.events?.onRegionDarknessChanged(smallClockIsDark)
clock?.largeClock?.events?.onRegionDarknessChanged(largeClockIsDark)
}
- private fun updateRegionSamplers(currentClock: ClockController?) {
- smallRegionSampler?.stopRegionSampler()
- largeRegionSampler?.stopRegionSampler()
-
- smallRegionSampler = createRegionSampler(
- currentClock?.smallClock?.view,
- mainExecutor,
- bgExecutor,
- regionSamplingEnabled,
- ::updateColors
- )
-
- largeRegionSampler = createRegionSampler(
- currentClock?.largeClock?.view,
- mainExecutor,
- bgExecutor,
- regionSamplingEnabled,
- ::updateColors
- )
-
- smallRegionSampler!!.startRegionSampler()
- largeRegionSampler!!.startRegionSampler()
+ private fun updateRegionSampler(sampledRegion: View) {
+ regionSampler?.stopRegionSampler()
+ regionSampler = createRegionSampler(
+ sampledRegion,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ ::updateColors
+ )?.apply { startRegionSampler() }
updateColors()
}
@@ -155,7 +199,7 @@
bgExecutor: Executor?,
regionSamplingEnabled: Boolean,
updateColors: () -> Unit
- ): RegionSampler {
+ ): RegionSampler? {
return RegionSampler(
sampledView,
mainExecutor,
@@ -164,8 +208,7 @@
updateColors)
}
- var smallRegionSampler: RegionSampler? = null
- var largeRegionSampler: RegionSampler? = null
+ var regionSampler: RegionSampler? = null
private var smallClockIsDark = true
private var largeClockIsDark = true
@@ -232,8 +275,6 @@
configurationController.addCallback(configListener)
batteryController.addCallback(batteryCallback)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
- smallRegionSampler?.startRegionSampler()
- largeRegionSampler?.startRegionSampler()
disposableHandle = parent.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
listenForDozing(this)
@@ -258,8 +299,7 @@
configurationController.removeCallback(configListener)
batteryController.removeCallback(batteryCallback)
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
- smallRegionSampler?.stopRegionSampler()
- largeRegionSampler?.stopRegionSampler()
+ regionSampler?.stopRegionSampler()
}
private fun updateFontSizes() {
@@ -275,8 +315,7 @@
fun dump(pw: PrintWriter) {
pw.println(this)
clock?.dump(pw)
- smallRegionSampler?.dump(pw)
- largeRegionSampler?.dump(pw)
+ regionSampler?.dump(pw)
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index b159714..35cae09 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -47,7 +47,6 @@
import com.android.systemui.R;
import java.util.ArrayList;
-import java.util.Stack;
/**
* A View similar to a textView which contains password text and can animate when the text is
@@ -92,7 +91,6 @@
private final int mGravity;
private ArrayList<CharState> mTextChars = new ArrayList<>();
private String mText = "";
- private Stack<CharState> mCharPool = new Stack<>();
private int mDotSize;
private PowerManager mPM;
private int mCharPadding;
@@ -310,13 +308,7 @@
}
private CharState obtainCharState(char c) {
- CharState charState;
- if(mCharPool.isEmpty()) {
- charState = new CharState();
- } else {
- charState = mCharPool.pop();
- charState.reset();
- }
+ CharState charState = new CharState();
charState.whichChar = c;
return charState;
}
@@ -343,8 +335,6 @@
maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
charState.startRemoveAnimation(startDelay, maxDelay);
charState.removeDotSwapCallbacks();
- } else {
- mCharPool.push(charState);
}
}
if (!animated) {
@@ -421,8 +411,6 @@
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
mTextChars.remove(CharState.this);
- mCharPool.push(CharState.this);
- reset();
cancelAnimator(textTranslateAnimator);
textTranslateAnimator = null;
}
@@ -518,21 +506,6 @@
}
};
- void reset() {
- whichChar = 0;
- currentTextSizeFactor = 0.0f;
- currentDotSizeFactor = 0.0f;
- currentWidthFactor = 0.0f;
- cancelAnimator(textAnimator);
- textAnimator = null;
- cancelAnimator(dotAnimator);
- dotAnimator = null;
- cancelAnimator(widthAnimator);
- widthAnimator = null;
- currentTextTranslationY = 1.0f;
- removeDotSwapCallbacks();
- }
-
void startRemoveAnimation(long startDelay, long widthDelay) {
boolean dotNeedsAnimation = (currentDotSizeFactor > 0.0f && dotAnimator == null)
|| (dotAnimator != null && dotAnimationIsGrowing);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index c5d4bbe..46cc894 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -207,7 +207,8 @@
// Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references.
mNotificationShadeCallback =
- (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) ->
+ (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded,
+ isDreaming) ->
registerOrUnregisterDismissNotificationShadeAction();
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
index 3a01cd5..39ea936 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
@@ -54,9 +54,12 @@
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN,
- MotionEvent.ACTION_MOVE -> processActionMove(preprocess())
+ MotionEvent.ACTION_MOVE,
+ MotionEvent.ACTION_HOVER_ENTER,
+ MotionEvent.ACTION_HOVER_MOVE -> processActionMove(preprocess())
MotionEvent.ACTION_UP,
- MotionEvent.ACTION_POINTER_UP ->
+ MotionEvent.ACTION_POINTER_UP,
+ MotionEvent.ACTION_HOVER_EXIT ->
processActionUp(preprocess(), event.getPointerId(event.actionIndex))
MotionEvent.ACTION_CANCEL -> processActionCancel(NormalizedTouchData())
else ->
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
index 1454210..fb0c0a6 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
@@ -20,7 +20,7 @@
import android.content.res.Configuration
import android.graphics.PixelFormat
import android.os.SystemProperties
-import android.util.DisplayMetrics
+import android.view.Surface
import android.view.View
import android.view.WindowManager
import com.android.internal.annotations.VisibleForTesting
@@ -36,7 +36,6 @@
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import javax.inject.Inject
@@ -172,30 +171,28 @@
}
private fun layoutRipple() {
- val displayMetrics = DisplayMetrics()
- context.display.getRealMetrics(displayMetrics)
- val width = displayMetrics.widthPixels
- val height = displayMetrics.heightPixels
+ val bounds = windowManager.currentWindowMetrics.bounds
+ val width = bounds.width()
+ val height = bounds.height()
val maxDiameter = Integer.max(width, height) * 2f
rippleView.setMaxSize(maxDiameter, maxDiameter)
- when (RotationUtils.getExactRotation(context)) {
- RotationUtils.ROTATION_LANDSCAPE -> {
+ when (context.display.rotation) {
+ Surface.ROTATION_0 -> {
+ rippleView.setCenter(
+ width * normalizedPortPosX, height * normalizedPortPosY)
+ }
+ Surface.ROTATION_90 -> {
rippleView.setCenter(
width * normalizedPortPosY, height * (1 - normalizedPortPosX))
}
- RotationUtils.ROTATION_UPSIDE_DOWN -> {
+ Surface.ROTATION_180 -> {
rippleView.setCenter(
width * (1 - normalizedPortPosX), height * (1 - normalizedPortPosY))
}
- RotationUtils.ROTATION_SEASCAPE -> {
+ Surface.ROTATION_270 -> {
rippleView.setCenter(
width * (1 - normalizedPortPosY), height * normalizedPortPosX)
}
- else -> {
- // ROTATION_NONE
- rippleView.setCenter(
- width * normalizedPortPosX, height * normalizedPortPosY)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index f29f6d0..822190f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -188,6 +188,8 @@
/** See [ControlsUiController.getPreferredSelectedItem]. */
fun getPreferredSelection(): SelectedItem
+ fun setPreferredSelection(selectedItem: SelectedItem)
+
/**
* Bind to a service that provides a Device Controls panel (embedded activity). This will allow
* the app to remain "warm", and reduce latency.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 49771dd..ce82af7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -37,6 +37,7 @@
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.SysUISingleton
@@ -63,6 +64,7 @@
private val listingController: ControlsListingController,
private val userFileManager: UserFileManager,
private val userTracker: UserTracker,
+ private val authorizedPanelsRepository: AuthorizedPanelsRepository,
optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
dumpManager: DumpManager,
) : Dumpable, ControlsController {
@@ -251,6 +253,11 @@
private fun resetFavorites() {
Favorites.clear()
Favorites.load(persistenceWrapper.readFavorites())
+ // After loading favorites, add the package names of any apps with favorites to the list
+ // of authorized panels. That way, if the user has previously favorited controls for an app,
+ // that panel will be authorized.
+ authorizedPanelsRepository.addAuthorizedPanels(
+ Favorites.getAllStructures().map { it.componentName.packageName }.toSet())
}
private fun confirmAvailability(): Boolean {
@@ -491,6 +498,7 @@
if (!confirmAvailability()) return
executor.execute {
if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(componentName.packageName))
persistenceWrapper.storeFavorites(Favorites.getAllStructures())
}
}
@@ -557,6 +565,10 @@
return uiController.getPreferredSelectedItem(getFavorites())
}
+ override fun setPreferredSelection(selectedItem: SelectedItem) {
+ uiController.updatePreferences(selectedItem)
+ }
+
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("ControlsController state:")
pw.println(" Changing users: $userChanging")
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index 6d6410d..6af8e73 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -34,6 +34,8 @@
import com.android.systemui.controls.management.ControlsListingControllerImpl
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.management.ControlsRequestDialog
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.AuthorizedPanelsRepositoryImpl
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
import com.android.systemui.controls.ui.ControlActionCoordinator
@@ -104,6 +106,11 @@
coordinator: ControlActionCoordinatorImpl
): ControlActionCoordinator
+ @Binds
+ abstract fun provideAuthorizedPanelsRepository(
+ repository: AuthorizedPanelsRepositoryImpl
+ ): AuthorizedPanelsRepository
+
@BindsOptionalOf
abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index 753d5ad..3fe0f03 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -45,14 +45,15 @@
* @param onAppSelected a callback to indicate that an app has been selected in the list.
*/
class AppAdapter(
- backgroundExecutor: Executor,
- uiExecutor: Executor,
- lifecycle: Lifecycle,
- controlsListingController: ControlsListingController,
- private val layoutInflater: LayoutInflater,
- private val onAppSelected: (ComponentName?) -> Unit = {},
- private val favoritesRenderer: FavoritesRenderer,
- private val resources: Resources
+ backgroundExecutor: Executor,
+ uiExecutor: Executor,
+ lifecycle: Lifecycle,
+ controlsListingController: ControlsListingController,
+ private val layoutInflater: LayoutInflater,
+ private val onAppSelected: (ControlsServiceInfo) -> Unit = {},
+ private val favoritesRenderer: FavoritesRenderer,
+ private val resources: Resources,
+ private val authorizedPanels: Set<String> = emptySet(),
) : RecyclerView.Adapter<AppAdapter.Holder>() {
private var listOfServices = emptyList<ControlsServiceInfo>()
@@ -64,8 +65,10 @@
val localeComparator = compareBy<ControlsServiceInfo, CharSequence>(collator) {
it.loadLabel() ?: ""
}
- listOfServices = serviceInfos.filter { it.panelActivity == null }
- .sortedWith(localeComparator)
+ // No panel or the panel is not authorized
+ listOfServices = serviceInfos.filter {
+ it.panelActivity == null || it.panelActivity?.packageName !in authorizedPanels
+ }.sortedWith(localeComparator)
uiExecutor.execute(::notifyDataSetChanged)
}
}
@@ -86,8 +89,8 @@
override fun onBindViewHolder(holder: Holder, index: Int) {
holder.bindData(listOfServices[index])
- holder.itemView.setOnClickListener {
- onAppSelected(ComponentName.unflattenFromString(listOfServices[index].key))
+ holder.view.setOnClickListener {
+ onAppSelected(listOfServices[index])
}
}
@@ -95,6 +98,8 @@
* Holder for binding views in the [RecyclerView]-
*/
class Holder(view: View, val favRenderer: FavoritesRenderer) : RecyclerView.ViewHolder(view) {
+ val view: View = itemView
+
private val icon: ImageView = itemView.requireViewById(com.android.internal.R.id.icon)
private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title)
private val favorites: TextView = itemView.requireViewById(R.id.favorites)
@@ -106,7 +111,11 @@
fun bindData(data: ControlsServiceInfo) {
icon.setImageDrawable(data.loadIcon())
title.text = data.loadLabel()
- val text = favRenderer.renderFavoritesForComponent(data.componentName)
+ val text = if (data.panelActivity == null) {
+ favRenderer.renderFavoritesForComponent(data.componentName)
+ } else {
+ null
+ }
favorites.text = text
favorites.visibility = if (text == null) View.GONE else View.VISIBLE
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 90bc5d0..54587b2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.app.ActivityOptions
+import android.app.Dialog
import android.content.ComponentName
import android.content.Context
import android.content.Intent
@@ -31,12 +32,15 @@
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.activity.ComponentActivity
+import androidx.annotation.VisibleForTesting
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
+import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.ui.ControlsActivity
-import com.android.systemui.controls.ui.ControlsUiController
+import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
@@ -52,7 +56,8 @@
private val listingController: ControlsListingController,
private val controlsController: ControlsController,
private val userTracker: UserTracker,
- private val uiController: ControlsUiController
+ private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ private val panelConfirmationDialogFactory: PanelConfirmationDialogFactory
) : ComponentActivity() {
companion object {
@@ -72,6 +77,7 @@
}
}
}
+ private var dialog: Dialog? = null
private val mOnBackInvokedCallback = OnBackInvokedCallback {
if (DEBUG) {
@@ -138,9 +144,11 @@
lifecycle,
listingController,
LayoutInflater.from(this),
- ::launchFavoritingActivity,
+ ::onAppSelected,
FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
- resources).apply {
+ resources,
+ authorizedPanelsRepository.getAuthorizedPanels()
+ ).apply {
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
var hasAnimated = false
override fun onChanged() {
@@ -167,13 +175,35 @@
Log.d(TAG, "Unregistered onBackInvokedCallback")
}
onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
+ dialog?.cancel()
+ }
+
+ fun onAppSelected(serviceInfo: ControlsServiceInfo) {
+ dialog?.cancel()
+ if (serviceInfo.panelActivity == null) {
+ launchFavoritingActivity(serviceInfo.componentName)
+ } else {
+ val appName = serviceInfo.loadLabel() ?: ""
+ dialog = panelConfirmationDialogFactory.createConfirmationDialog(this, appName) { ok ->
+ if (ok) {
+ authorizedPanelsRepository.addAuthorizedPanels(
+ setOf(serviceInfo.componentName.packageName)
+ )
+ animateExitAndFinish()
+ val selected = SelectedItem.PanelItem(appName, componentName)
+ controlsController.setPreferredSelection(selected)
+ openControlsOrigin()
+ }
+ dialog = null
+ }.also { it.show() }
+ }
}
/**
* Launch the [ControlsFavoritingActivity] for the specified component.
* @param component a component name for a [ControlsProviderService]
*/
- fun launchFavoritingActivity(component: ComponentName?) {
+ private fun launchFavoritingActivity(component: ComponentName?) {
executor.execute {
component?.let {
val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
@@ -194,7 +224,15 @@
super.onDestroy()
}
- private fun animateExitAndFinish() {
+ private fun openControlsOrigin() {
+ startActivity(
+ Intent(applicationContext, ControlsActivity::class.java),
+ ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
+ )
+ }
+
+ @VisibleForTesting
+ internal open fun animateExitAndFinish() {
val rootView = requireViewById<ViewGroup>(R.id.controls_management_root)
ControlsAnimations.exitAnimation(
rootView,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt
new file mode 100644
index 0000000..6f87aa9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/**
+ * Factory to create dialogs for consenting to show app panels for specific apps.
+ *
+ * [internalDialogFactory] is for facilitating testing.
+ */
+class PanelConfirmationDialogFactory(
+ private val internalDialogFactory: (Context) -> SystemUIDialog
+) {
+ @Inject constructor() : this({ SystemUIDialog(it) })
+
+ /**
+ * Creates a dialog to show to the user. [response] will be true if an only if the user responds
+ * affirmatively.
+ */
+ fun createConfirmationDialog(
+ context: Context,
+ appName: CharSequence,
+ response: Consumer<Boolean>
+ ): Dialog {
+ val listener =
+ DialogInterface.OnClickListener { _, which ->
+ response.accept(which == DialogInterface.BUTTON_POSITIVE)
+ }
+ return internalDialogFactory(context).apply {
+ setTitle(this.context.getString(R.string.controls_panel_authorization_title, appName))
+ setMessage(this.context.getString(R.string.controls_panel_authorization, appName))
+ setCanceledOnTouchOutside(true)
+ setOnCancelListener { response.accept(false) }
+ setPositiveButton(R.string.controls_dialog_ok, listener)
+ setNeutralButton(R.string.cancel, listener)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
new file mode 100644
index 0000000..3e672f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.panels
+
+/**
+ * Repository for keeping track of which packages the panel has authorized to show control panels
+ * (embedded activity).
+ */
+interface AuthorizedPanelsRepository {
+
+ /** A set of package names that the user has previously authorized to show panels. */
+ fun getAuthorizedPanels(): Set<String>
+
+ /** Adds [packageNames] to the set of packages that the user has authorized to show panels. */
+ fun addAuthorizedPanels(packageNames: Set<String>)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
new file mode 100644
index 0000000..f7e43a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.android.systemui.R
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import javax.inject.Inject
+
+class AuthorizedPanelsRepositoryImpl
+@Inject
+constructor(
+ private val context: Context,
+ private val userFileManager: UserFileManager,
+ private val userTracker: UserTracker
+) : AuthorizedPanelsRepository {
+
+ override fun getAuthorizedPanels(): Set<String> {
+ return getAuthorizedPanelsInternal(instantiateSharedPrefs())
+ }
+
+ override fun addAuthorizedPanels(packageNames: Set<String>) {
+ addAuthorizedPanelsInternal(instantiateSharedPrefs(), packageNames)
+ }
+
+ private fun getAuthorizedPanelsInternal(sharedPreferences: SharedPreferences): Set<String> {
+ return sharedPreferences.getStringSet(KEY, emptySet())!!
+ }
+
+ private fun addAuthorizedPanelsInternal(
+ sharedPreferences: SharedPreferences,
+ packageNames: Set<String>
+ ) {
+ val currentSet = getAuthorizedPanelsInternal(sharedPreferences)
+ sharedPreferences.edit().putStringSet(KEY, currentSet + packageNames).apply()
+ }
+
+ private fun instantiateSharedPrefs(): SharedPreferences {
+ val sharedPref =
+ userFileManager.getSharedPreferences(
+ DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ Context.MODE_PRIVATE,
+ userTracker.userId,
+ )
+
+ // If we've never run this (i.e., the key doesn't exist), add the default packages
+ if (sharedPref.getStringSet(KEY, null) == null) {
+ sharedPref
+ .edit()
+ .putStringSet(
+ KEY,
+ context.resources
+ .getStringArray(R.array.config_controlsPreferredPackages)
+ .toSet()
+ )
+ .apply()
+ }
+ return sharedPref
+ }
+
+ companion object {
+ private const val KEY = "authorized_panels"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index f5c5905..c1cec9d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -58,6 +58,8 @@
* This element will be the one that appears when the user first opens the controls activity.
*/
fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem
+
+ fun updatePreferences(selectedItem: SelectedItem)
}
sealed class SelectedItem {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 6289788..966dbf1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -60,10 +60,13 @@
import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.globalactions.GlobalActionsPopupMenu
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserFileManager
@@ -99,6 +102,8 @@
private val userTracker: UserTracker,
private val taskViewFactory: Optional<TaskViewFactory>,
private val controlsSettingsRepository: ControlsSettingsRepository,
+ private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ private val featureFlags: FeatureFlags,
dumpManager: DumpManager
) : ControlsUiController, Dumpable {
@@ -160,6 +165,7 @@
): ControlsListingController.ControlsListingCallback {
return object : ControlsListingController.ControlsListingCallback {
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
+ val authorizedPanels = authorizedPanelsRepository.getAuthorizedPanels()
val lastItems = serviceInfos.map {
val uid = it.serviceInfo.applicationInfo.uid
@@ -169,7 +175,11 @@
it.loadIcon(),
it.componentName,
uid,
- it.panelActivity
+ if (it.componentName.packageName in authorizedPanels) {
+ it.panelActivity
+ } else {
+ null
+ }
)
}
uiExecutor.execute {
@@ -417,14 +427,20 @@
val isPanel = selectedItem is SelectedItem.PanelItem
val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
?: EMPTY_STRUCTURE
+ val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
+ val addControlsId = if (newFlows || isPanel) {
+ R.string.controls_menu_add_another_app
+ } else {
+ R.string.controls_menu_add
+ }
val items = if (isPanel) {
arrayOf(
- context.resources.getString(R.string.controls_menu_add),
+ context.resources.getString(addControlsId),
)
} else {
arrayOf(
- context.resources.getString(R.string.controls_menu_add),
+ context.resources.getString(addControlsId),
context.resources.getString(R.string.controls_menu_edit)
)
}
@@ -449,7 +465,7 @@
when (pos) {
// 0: Add Control
0 -> {
- if (isPanel) {
+ if (isPanel || newFlows) {
startProviderSelectorActivity()
} else {
startFavoritingActivity(selectedStructure)
@@ -610,11 +626,11 @@
}
}
- private fun updatePreferences(si: SelectedItem) {
+ override fun updatePreferences(selectedItem: SelectedItem) {
sharedPreferences.edit()
- .putString(PREF_COMPONENT, si.componentName.flattenToString())
- .putString(PREF_STRUCTURE_OR_APP_NAME, si.name.toString())
- .putBoolean(PREF_IS_PANEL, si is SelectedItem.PanelItem)
+ .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
+ .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
+ .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
.commit()
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 9cbc64e..c9e5449 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -28,6 +28,7 @@
import com.android.systemui.biometrics.UdfpsOverlay
import com.android.systemui.clipboardoverlay.ClipboardListener
import com.android.systemui.dagger.qualifiers.PerUser
+import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
@@ -293,4 +294,10 @@
@IntoMap
@ClassKey(StylusUsiPowerStartable::class)
abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
+
+ /**Inject into DreamMonitor */
+ @Binds
+ @IntoMap
+ @ClassKey(DreamMonitor::class)
+ abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
new file mode 100644
index 0000000..102f208
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import android.util.Log;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback;
+import com.android.systemui.dreams.conditions.DreamCondition;
+import com.android.systemui.shared.condition.Monitor;
+
+import javax.inject.Inject;
+
+/**
+ * A {@link CoreStartable} to retain a monitor for tracking dreaming.
+ */
+public class DreamMonitor implements CoreStartable {
+ private static final String TAG = "DreamMonitor";
+
+ // We retain a reference to the monitor so it is not garbage-collected.
+ private final Monitor mConditionMonitor;
+ private final DreamCondition mDreamCondition;
+ private final DreamStatusBarStateCallback mCallback;
+
+
+ @Inject
+ public DreamMonitor(Monitor monitor, DreamCondition dreamCondition,
+ DreamStatusBarStateCallback callback) {
+ mConditionMonitor = monitor;
+ mDreamCondition = dreamCondition;
+ mCallback = callback;
+
+ }
+ @Override
+ public void start() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "started");
+ }
+
+ mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback)
+ .addCondition(mDreamCondition)
+ .build());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
new file mode 100644
index 0000000..c8c9470
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.dreams.callbacks;
+
+import android.util.Log;
+
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+
+import javax.inject.Inject;
+
+/**
+ * A callback that informs {@link SysuiStatusBarStateController} when the dream state has changed.
+ */
+public class DreamStatusBarStateCallback implements Monitor.Callback {
+ private static final String TAG = "DreamStatusBarCallback";
+
+ private final SysuiStatusBarStateController mStateController;
+
+ @Inject
+ public DreamStatusBarStateCallback(SysuiStatusBarStateController statusBarStateController) {
+ mStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onConditionsChanged(boolean allConditionsMet) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onConditionChanged:" + allConditionsMet);
+ }
+
+ mStateController.setIsDreaming(allConditionsMet);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
new file mode 100644
index 0000000..2befce7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.dreams.conditions;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.TextUtils;
+
+import com.android.systemui.shared.condition.Condition;
+
+import javax.inject.Inject;
+
+/**
+ * {@link DreamCondition} provides a signal when a dream begins and ends.
+ */
+public class DreamCondition extends Condition {
+ private final Context mContext;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ processIntent(intent);
+ }
+ };
+
+ @Inject
+ public DreamCondition(Context context) {
+ mContext = context;
+ }
+
+ private void processIntent(Intent intent) {
+ // In the case of a non-existent sticky broadcast, ignore when there is no intent.
+ if (intent == null) {
+ return;
+ }
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) {
+ updateCondition(true);
+ } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) {
+ updateCondition(false);
+ } else {
+ throw new IllegalStateException("unexpected intent:" + intent);
+ }
+ }
+
+ @Override
+ protected void start() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ final Intent stickyIntent = mContext.registerReceiver(mReceiver, filter);
+ processIntent(stickyIntent);
+ }
+
+ @Override
+ protected void stop() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5d85fc96..108a0e8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -65,8 +65,7 @@
val FSI_ON_DND_UPDATE = unreleasedFlag(259130119, "fsi_on_dnd_update", teamfood = true)
// TODO(b/265804648): Tracking Bug
- @JvmField
- val DISABLE_FSI = unreleasedFlag(265804648, "disable_fsi")
+ @JvmField val DISABLE_FSI = unreleasedFlag(265804648, "disable_fsi")
// TODO(b/254512538): Tracking Bug
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true)
@@ -104,7 +103,7 @@
unreleasedFlag(174148361, "notification_inline_reply_animation", teamfood = true)
val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD =
- unreleasedFlag(254647461, "filter_unseen_notifs_on_keyguard", teamfood = true)
+ releasedFlag(254647461, "filter_unseen_notifs_on_keyguard", teamfood = true)
// TODO(b/263414400): Tracking Bug
@JvmField
@@ -217,6 +216,11 @@
val ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS =
unreleasedFlag(226, "enable_wallet_contextual_loyalty_cards", teamfood = false)
+ // TODO(b/242908637): Tracking Bug
+ @JvmField
+ val WALLPAPER_FULLSCREEN_PREVIEW =
+ unreleasedFlag(227, "wallpaper_fullscreen_preview", teamfood = true)
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -226,11 +230,11 @@
// TODO(b/254513100): Tracking Bug
val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
releasedFlag(401, "smartspace_shared_element_transition_enabled")
- val SMARTSPACE = resourceBooleanFlag(402, R.bool.flag_smartspace, "smartspace")
// TODO(b/258517050): Clean up after the feature is launched.
@JvmField
- val SMARTSPACE_DATE_WEATHER_DECOUPLED = unreleasedFlag(403, "smartspace_date_weather_decoupled")
+ val SMARTSPACE_DATE_WEATHER_DECOUPLED =
+ sysPropBooleanFlag(403, "persist.sysui.ss.dw_decoupled", default = false)
// 500 - quick settings
@@ -348,6 +352,9 @@
val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE =
unreleasedFlag(912, "media_ttt_dismiss_gesture", teamfood = true)
+ // TODO(b/266157412): Tracking Bug
+ val MEDIA_RETAIN_SESSIONS = unreleasedFlag(913, "media_retain_sessions")
+
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
@@ -361,7 +368,7 @@
@Keep
@JvmField
val WM_ENABLE_SHELL_TRANSITIONS =
- sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = false)
+ sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = true)
// TODO(b/254513207): Tracking Bug
@Keep
@@ -463,12 +470,30 @@
val WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM =
unreleasedFlag(1206, "persist.wm.debug.predictive_back_bouncer_anim", teamfood = true)
+ // TODO(b/238475428): Tracking Bug
+ @JvmField
+ val WM_SHADE_ALLOW_BACK_GESTURE =
+ unreleasedFlag(1207, "persist.wm.debug.shade_allow_back_gesture", teamfood = false)
+
+ // TODO(b/238475428): Tracking Bug
+ @JvmField
+ val WM_SHADE_ANIMATE_BACK_GESTURE =
+ unreleasedFlag(1208, "persist.wm.debug.shade_animate_back_gesture", teamfood = true)
+
+ // TODO(b/265639042): Tracking Bug
+ @JvmField
+ val WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM =
+ unreleasedFlag(1209, "persist.wm.debug.predictive_back_qs_dialog_anim", teamfood = true)
+
// 1300 - screenshots
// TODO(b/254513155): Tracking Bug
@JvmField
val SCREENSHOT_WORK_PROFILE_POLICY =
unreleasedFlag(1301, "screenshot_work_profile_policy", teamfood = true)
+ // TODO(b/264916608): Tracking Bug
+ @JvmField val SCREENSHOT_METADATA = unreleasedFlag(1302, "screenshot_metadata")
+
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
val QUICK_TAP_IN_PCC = releasedFlag(1400, "quick_tap_in_pcc")
@@ -494,6 +519,8 @@
// 1800 - shade container
@JvmField
val LEAVE_SHADE_OPEN_FOR_BUGREPORT = releasedFlag(1800, "leave_shade_open_for_bugreport")
+ // TODO(b/265944639): Tracking Bug
+ @JvmField val DUAL_SHADE = releasedFlag(1801, "dual_shade")
// 1900
@JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
@@ -505,6 +532,10 @@
val APP_PANELS_ALL_APPS_ALLOWED =
releasedFlag(2001, "app_panels_all_apps_allowed", teamfood = true)
+ @JvmField
+ val CONTROLS_MANAGEMENT_NEW_FLOWS =
+ unreleasedFlag(2002, "controls_management_new_flows", teamfood = true)
+
// 2100 - Falsing Manager
@JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
@@ -554,6 +585,5 @@
// 2600 - keyboard shortcut
// TODO(b/259352579): Tracking Bug
- @JvmField
- val SHORTCUT_LIST_SEARCH_LAYOUT = unreleasedFlag(2600, "shortcut_list_search_layout")
+ @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = unreleasedFlag(2600, "shortcut_list_search_layout")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 14f918d..b5bcd45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -45,6 +45,27 @@
override fun start() {
listenForGoneToAodOrDozing()
listenForGoneToDreaming()
+ listenForGoneToLockscreen()
+ }
+
+ // Primarily for when the user chooses to lock down the device
+ private fun listenForGoneToLockscreen() {
+ scope.launch {
+ keyguardInteractor.isKeyguardShowing
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isKeyguardShowing, lastStartedStep) ->
+ if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.GONE,
+ KeyguardState.LOCKSCREEN,
+ getAnimator(),
+ )
+ )
+ }
+ }
+ }
}
private fun listenForGoneToDreaming() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index c219380..9ddc575 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -363,6 +363,10 @@
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED,
value = featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
),
+ KeyguardPickerFlag(
+ name = Contract.FlagsTable.FLAG_NAME_WALLPAPER_FULLSCREEN_PREVIEW,
+ value = featureFlags.isEnabled(Flags.WALLPAPER_FULLSCREEN_PREVIEW),
+ ),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 6a5e725..da2164e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -304,6 +304,7 @@
mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
updateState(key, state)
}
+ mediaTimeoutListener.sessionCallback = { key: String -> onSessionDestroyed(key) }
mediaResumeListener.setManager(this)
mediaDataFilter.mediaDataManager = this
@@ -1292,45 +1293,106 @@
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
- val removed = mediaEntries.remove(key)
- if (useMediaResumption && removed?.resumeAction != null && removed.isLocalSession()) {
- Log.d(TAG, "Not removing $key because resumable")
- // Move to resume key (aka package name) if that key doesn't already exist.
- val resumeAction = getResumeMediaAction(removed.resumeAction!!)
- val updated =
- removed.copy(
- token = null,
- actions = listOf(resumeAction),
- semanticActions = MediaButton(playOrPause = resumeAction),
- actionsToShowInCompact = listOf(0),
- active = false,
- resumption = true,
- isPlaying = false,
- isClearable = true
- )
- val pkg = removed.packageName
- val migrate = mediaEntries.put(pkg, updated) == null
- // Notify listeners of "new" controls when migrating or removed and update when not
- if (migrate) {
- notifyMediaDataLoaded(pkg, key, updated)
- } else {
- // Since packageName is used for the key of the resumption controls, it is
- // possible that another notification has already been reused for the resumption
- // controls of this package. In this case, rather than renaming this player as
- // packageName, just remove it and then send a update to the existing resumption
- // controls.
- notifyMediaDataRemoved(key)
- notifyMediaDataLoaded(pkg, pkg, updated)
- }
- logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
- return
- }
- if (removed != null) {
+ val removed = mediaEntries.remove(key) ?: return
+
+ if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
+ convertToResumePlayer(removed)
+ } else if (mediaFlags.isRetainingPlayersEnabled()) {
+ handlePossibleRemoval(removed, notificationRemoved = true)
+ } else {
notifyMediaDataRemoved(key)
logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
}
}
+ private fun onSessionDestroyed(key: String) {
+ if (!mediaFlags.isRetainingPlayersEnabled()) return
+
+ if (DEBUG) Log.d(TAG, "session destroyed for $key")
+ val entry = mediaEntries.remove(key) ?: return
+ // Clear token since the session is no longer valid
+ val updated = entry.copy(token = null)
+ handlePossibleRemoval(updated)
+ }
+
+ /**
+ * Convert to resume state if the player is no longer valid and active, then notify listeners
+ * that the data was updated. Does not convert to resume state if the player is still valid, or
+ * if it was removed before becoming inactive. (Assumes that [removed] was removed from
+ * [mediaEntries] before this function was called)
+ */
+ private fun handlePossibleRemoval(removed: MediaData, notificationRemoved: Boolean = false) {
+ val key = removed.notificationKey!!
+ val hasSession = removed.token != null
+ if (hasSession && removed.semanticActions != null) {
+ // The app was using session actions, and the session is still valid: keep player
+ if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
+ mediaEntries.put(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (!notificationRemoved && removed.semanticActions == null) {
+ // The app was using notification actions, and notif wasn't removed yet: keep player
+ if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
+ mediaEntries.put(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (removed.active) {
+ // This player was still active - it didn't last long enough to time out: remove
+ if (DEBUG) Log.d(TAG, "Removing still-active player $key")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ } else {
+ // Convert to resume
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Notification ($notificationRemoved) and/or session " +
+ "($hasSession) gone for inactive player $key"
+ )
+ }
+ convertToResumePlayer(removed)
+ }
+ }
+
+ /** Set the given [MediaData] as a resume state player and notify listeners */
+ private fun convertToResumePlayer(data: MediaData) {
+ val key = data.notificationKey!!
+ if (DEBUG) Log.d(TAG, "Converting $key to resume")
+ // Move to resume key (aka package name) if that key doesn't already exist.
+ val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) }
+ val actions = resumeAction?.let { listOf(resumeAction) } ?: emptyList()
+ val launcherIntent =
+ context.packageManager.getLaunchIntentForPackage(data.packageName)?.let {
+ PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE)
+ }
+ val updated =
+ data.copy(
+ token = null,
+ actions = actions,
+ semanticActions = MediaButton(playOrPause = resumeAction),
+ actionsToShowInCompact = listOf(0),
+ active = false,
+ resumption = true,
+ isPlaying = false,
+ isClearable = true,
+ clickIntent = launcherIntent,
+ )
+ val pkg = data.packageName
+ val migrate = mediaEntries.put(pkg, updated) == null
+ // Notify listeners of "new" controls when migrating or removed and update when not
+ Log.d(TAG, "migrating? $migrate from $key -> $pkg")
+ if (migrate) {
+ notifyMediaDataLoaded(key = pkg, oldKey = key, info = updated)
+ } else {
+ // Since packageName is used for the key of the resumption controls, it is
+ // possible that another notification has already been reused for the resumption
+ // controls of this package. In this case, rather than renaming this player as
+ // packageName, just remove it and then send a update to the existing resumption
+ // controls.
+ notifyMediaDataRemoved(key)
+ notifyMediaDataLoaded(key = pkg, oldKey = pkg, info = updated)
+ }
+ logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
+ }
+
fun setMediaResumptionEnabled(isEnabled: Boolean) {
if (useMediaResumption == isEnabled) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
index 7f5c82f..a898b00 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
@@ -71,6 +71,12 @@
*/
lateinit var stateCallback: (String, PlaybackState) -> Unit
+ /**
+ * Callback representing that the [MediaSession] for an active control has been destroyed
+ * @param key Media control unique identifier
+ */
+ lateinit var sessionCallback: (String) -> Unit
+
init {
statusBarStateController.addCallback(
object : StatusBarStateController.StateListener {
@@ -211,6 +217,7 @@
} else {
// For active controls, if the session is destroyed, clean up everything since we
// will need to recreate it if this key is updated later
+ sessionCallback.invoke(key)
destroy()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index 5c65c8b..4827a16 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -230,7 +230,14 @@
fun updateColorScheme(colorScheme: ColorScheme?): Boolean {
var anyChanged = false
- colorTransitions.forEach { anyChanged = it.updateColorScheme(colorScheme) || anyChanged }
+ colorTransitions.forEach {
+ val isChanged = it.updateColorScheme(colorScheme)
+
+ // Ignore changes to colorSeamless, since that is expected when toggling dark mode
+ if (it == colorSeamless) return@forEach
+
+ anyChanged = isChanged || anyChanged
+ }
colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme }
return anyChanged
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 5bc35ca..ab03930 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -45,4 +45,10 @@
/** Check whether we show explicit indicator on UMO */
fun isExplicitIndicatorEnabled() = featureFlags.isEnabled(Flags.MEDIA_EXPLICIT_INDICATOR)
+
+ /**
+ * If true, keep active media controls for the lifetime of the MediaSession, regardless of
+ * whether the underlying notification was dismissed
+ */
+ fun isRetainingPlayersEnabled() = featureFlags.isEnabled(Flags.MEDIA_RETAIN_SESSIONS)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a9e1a4d..4803371 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -95,6 +95,7 @@
private RecyclerView mDevicesRecyclerView;
private LinearLayout mDeviceListLayout;
private LinearLayout mCastAppLayout;
+ private LinearLayout mMediaMetadataSectionLayout;
private Button mDoneButton;
private Button mStopButton;
private Button mAppButton;
@@ -240,6 +241,7 @@
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
+ mMediaMetadataSectionLayout = mDialogView.requireViewById(R.id.media_metadata_section);
mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
mDoneButton = mDialogView.requireViewById(R.id.done);
mStopButton = mDialogView.requireViewById(R.id.stop);
@@ -255,21 +257,17 @@
mDevicesRecyclerView.setLayoutManager(mLayoutManager);
mDevicesRecyclerView.setAdapter(mAdapter);
mDevicesRecyclerView.setHasFixedSize(false);
- // Init header icon
- mHeaderIcon.setOnClickListener(v -> onHeaderIconClick());
// Init bottom buttons
mDoneButton.setOnClickListener(v -> dismiss());
mStopButton.setOnClickListener(v -> {
mMediaOutputController.releaseSession();
dismiss();
});
- mAppButton.setOnClickListener(v -> {
- mBroadcastSender.closeSystemDialogs();
- if (mMediaOutputController.getAppLaunchIntent() != null) {
- mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
- }
- dismiss();
- });
+ mAppButton.setOnClickListener(v -> mMediaOutputController.tryToLaunchMediaApplication());
+ if (mMediaOutputController.isAdvancedLayoutSupported()) {
+ mMediaMetadataSectionLayout.setOnClickListener(
+ v -> mMediaOutputController.tryToLaunchMediaApplication());
+ }
}
@Override
@@ -560,7 +558,7 @@
@Override
public void dismissDialog() {
- dismiss();
+ mBroadcastSender.closeSystemDialogs();
}
void onHeaderIconClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 9cf672b..1587e62 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -382,6 +382,15 @@
return mContext.getPackageManager().getLaunchIntentForPackage(mPackageName);
}
+ void tryToLaunchMediaApplication() {
+ Intent launchIntent = getAppLaunchIntent();
+ if (launchIntent != null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mCallback.dismissDialog();
+ mContext.startActivity(launchIntent);
+ }
+ }
+
CharSequence getHeaderTitle() {
if (mMediaController != null) {
final MediaMetadata metadata = mMediaController.getMetadata();
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 889147b..60dd5da 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -30,8 +30,8 @@
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
+import android.view.View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
import com.android.internal.widget.CachingIconView
-import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
@@ -78,6 +78,7 @@
private val viewUtil: ViewUtil,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
+ private val rippleController: MediaTttReceiverRippleController,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger<ChipReceiverInfo>>(
context,
logger,
@@ -114,9 +115,6 @@
}
}
- private var maxRippleWidth: Float = 0f
- private var maxRippleHeight: Float = 0f
-
private fun updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState displayState: Int,
routeInfo: MediaRoute2Info,
@@ -201,41 +199,44 @@
val iconView = currentView.getAppIconView()
iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
+ iconView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_ASSERTIVE
TintedIconViewBinder.bind(iconInfo.toTintedIcon(), iconView)
}
override fun animateViewIn(view: ViewGroup) {
val appIconView = view.getAppIconView()
- appIconView.animate()
- .translationYBy(-1 * getTranslationAmount().toFloat())
- .setDuration(ICON_TRANSLATION_ANIM_DURATION)
- .start()
- appIconView.animate()
- .alpha(1f)
- .setDuration(ICON_ALPHA_ANIM_DURATION)
- .start()
- // Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
- appIconView.postOnAnimation { view.requestAccessibilityFocus() }
- expandRipple(view.requireViewById(R.id.ripple))
+ val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
+ val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
+ animateViewTranslationAndFade(appIconView, -1 * getTranslationAmount(), 1f)
+ animateViewTranslationAndFade(iconRippleView, -1 * getTranslationAmount(), 1f)
+ rippleController.expandToInProgressState(rippleView, iconRippleView)
}
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
val appIconView = view.getAppIconView()
- appIconView.animate()
- .translationYBy(getTranslationAmount().toFloat())
- .setDuration(ICON_TRANSLATION_ANIM_DURATION)
- .start()
- appIconView.animate()
- .alpha(0f)
- .setDuration(ICON_ALPHA_ANIM_DURATION)
- .start()
-
+ val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
if (removalReason == ChipStateReceiver.TRANSFER_TO_RECEIVER_SUCCEEDED.name &&
mediaTttFlags.isMediaTttReceiverSuccessRippleEnabled()) {
- expandRippleToFull(rippleView, onAnimationEnd)
+ rippleController.expandToSuccessState(rippleView, onAnimationEnd)
+ animateViewTranslationAndFade(
+ iconRippleView,
+ -1 * getTranslationAmount(),
+ 0f,
+ translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ )
+ animateViewTranslationAndFade(
+ appIconView,
+ -1 * getTranslationAmount(),
+ 0f,
+ translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ )
} else {
- rippleView.collapseRipple(onAnimationEnd)
+ rippleController.collapseRipple(rippleView, onAnimationEnd)
+ animateViewTranslationAndFade(iconRippleView, getTranslationAmount(), 0f)
+ animateViewTranslationAndFade(appIconView, getTranslationAmount(), 0f)
}
}
@@ -245,74 +246,41 @@
viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
}
+ /** Animation of view translation and fading. */
+ private fun animateViewTranslationAndFade(
+ view: View,
+ translationYBy: Float,
+ alphaEndValue: Float,
+ translationDuration: Long = ICON_TRANSLATION_ANIM_DURATION,
+ alphaDuration: Long = ICON_ALPHA_ANIM_DURATION,
+ ) {
+ view.animate()
+ .translationYBy(translationYBy)
+ .setDuration(translationDuration)
+ .start()
+ view.animate()
+ .alpha(alphaEndValue)
+ .setDuration(alphaDuration)
+ .start()
+ }
+
/** Returns the amount that the chip will be translated by in its intro animation. */
- private fun getTranslationAmount(): Int {
- return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
- }
-
- private fun expandRipple(rippleView: ReceiverChipRippleView) {
- if (rippleView.rippleInProgress()) {
- // Skip if ripple is still playing
- return
- }
-
- // In case the device orientation changes, we need to reset the layout.
- rippleView.addOnLayoutChangeListener (
- View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
- if (v == null) return@OnLayoutChangeListener
-
- val layoutChangedRippleView = v as ReceiverChipRippleView
- layoutRipple(layoutChangedRippleView)
- layoutChangedRippleView.invalidate()
- }
- )
- rippleView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
- override fun onViewDetachedFromWindow(view: View?) {}
-
- override fun onViewAttachedToWindow(view: View?) {
- if (view == null) {
- return
- }
- val attachedRippleView = view as ReceiverChipRippleView
- layoutRipple(attachedRippleView)
- attachedRippleView.expandRipple()
- attachedRippleView.removeOnAttachStateChangeListener(this)
- }
- })
- }
-
- private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
- val windowBounds = windowManager.currentWindowMetrics.bounds
- val height = windowBounds.height().toFloat()
- val width = windowBounds.width().toFloat()
-
- if (isFullScreen) {
- maxRippleHeight = height * 2f
- maxRippleWidth = width * 2f
- } else {
- maxRippleHeight = height / 2f
- maxRippleWidth = width / 2f
- }
- rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
- // Center the ripple on the bottom of the screen in the middle.
- rippleView.setCenter(width * 0.5f, height)
- val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
- rippleView.setColor(color, 70)
+ private fun getTranslationAmount(): Float {
+ return rippleController.getRippleSize() * 0.5f -
+ rippleController.getReceiverIconSize()
}
private fun View.getAppIconView(): CachingIconView {
return this.requireViewById(R.id.app_icon)
}
- private fun expandRippleToFull(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
- layoutRipple(rippleView, true)
- rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
+ companion object {
+ private const val ICON_TRANSLATION_ANIM_DURATION = 500L
+ private const val ICON_TRANSLATION_SUCCEEDED_DURATION = 167L
+ private val ICON_ALPHA_ANIM_DURATION = 5.frames
}
}
-val ICON_TRANSLATION_ANIM_DURATION = 30.frames
-val ICON_ALPHA_ANIM_DURATION = 5.frames
-
data class ChipReceiverInfo(
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt
new file mode 100644
index 0000000..5013802
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.media.taptotransfer.receiver
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.view.View
+import android.view.WindowManager
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import javax.inject.Inject
+
+/**
+ * A controller responsible for the animation of the ripples shown in media tap-to-transfer on the
+ * receiving device.
+ */
+class MediaTttReceiverRippleController
+@Inject
+constructor(
+ private val context: Context,
+ private val windowManager: WindowManager,
+) {
+
+ private var maxRippleWidth: Float = 0f
+ private var maxRippleHeight: Float = 0f
+
+ /** Expands the icon and main ripple to in-progress state */
+ fun expandToInProgressState(
+ mainRippleView: ReceiverChipRippleView,
+ iconRippleView: ReceiverChipRippleView,
+ ) {
+ expandRipple(mainRippleView, isIconRipple = false)
+ expandRipple(iconRippleView, isIconRipple = true)
+ }
+
+ private fun expandRipple(rippleView: ReceiverChipRippleView, isIconRipple: Boolean) {
+ if (rippleView.rippleInProgress()) {
+ // Skip if ripple is still playing
+ return
+ }
+
+ // In case the device orientation changes, we need to reset the layout.
+ rippleView.addOnLayoutChangeListener(
+ View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
+ if (v == null) return@OnLayoutChangeListener
+
+ val layoutChangedRippleView = v as ReceiverChipRippleView
+ if (isIconRipple) {
+ layoutIconRipple(layoutChangedRippleView)
+ } else {
+ layoutRipple(layoutChangedRippleView)
+ }
+ layoutChangedRippleView.invalidate()
+ }
+ )
+ rippleView.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewDetachedFromWindow(view: View?) {}
+
+ override fun onViewAttachedToWindow(view: View?) {
+ if (view == null) {
+ return
+ }
+ val attachedRippleView = view as ReceiverChipRippleView
+ if (isIconRipple) {
+ layoutIconRipple(attachedRippleView)
+ } else {
+ layoutRipple(attachedRippleView)
+ }
+ attachedRippleView.expandRipple()
+ attachedRippleView.removeOnAttachStateChangeListener(this)
+ }
+ }
+ )
+ }
+
+ /** Expands the ripple to cover the screen. */
+ fun expandToSuccessState(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
+ layoutRipple(rippleView, isFullScreen = true)
+ rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
+ }
+
+ /** Collapses the ripple. */
+ fun collapseRipple(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable? = null) {
+ rippleView.collapseRipple(onAnimationEnd)
+ }
+
+ private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
+ val windowBounds = windowManager.currentWindowMetrics.bounds
+ val height = windowBounds.height().toFloat()
+ val width = windowBounds.width().toFloat()
+
+ if (isFullScreen) {
+ maxRippleHeight = height * 2f
+ maxRippleWidth = width * 2f
+ } else {
+ maxRippleHeight = getRippleSize()
+ maxRippleWidth = getRippleSize()
+ }
+ rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
+ // Center the ripple on the bottom of the screen in the middle.
+ rippleView.setCenter(width * 0.5f, height)
+ rippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
+ }
+
+ private fun layoutIconRipple(iconRippleView: ReceiverChipRippleView) {
+ val windowBounds = windowManager.currentWindowMetrics.bounds
+ val height = windowBounds.height().toFloat()
+ val width = windowBounds.width().toFloat()
+ val radius = getReceiverIconSize().toFloat()
+
+ iconRippleView.setMaxSize(radius * 0.8f, radius * 0.8f)
+ iconRippleView.setCenter(
+ width * 0.5f,
+ height - getReceiverIconSize() * 0.5f - getReceiverIconBottomMargin()
+ )
+ iconRippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
+ }
+
+ private fun getRippleColor(): Int {
+ var colorStateList =
+ ColorStateList.valueOf(
+ Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
+ )
+ return colorStateList.withLStar(TONE_PERCENT).defaultColor
+ }
+
+ /** Returns the size of the ripple. */
+ internal fun getRippleSize(): Float {
+ return getReceiverIconSize() * 4f
+ }
+
+ /** Returns the size of the icon of the receiver. */
+ internal fun getReceiverIconSize(): Int {
+ return context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
+ }
+
+ /** Return the bottom margin of the icon of the receiver. */
+ internal fun getReceiverIconBottomMargin(): Int {
+ // Adding a margin to make sure ripple behind the icon is not cut by the screen bounds.
+ return context.resources.getDimensionPixelSize(
+ R.dimen.media_ttt_receiver_icon_bottom_margin
+ )
+ }
+
+ companion object {
+ const val RIPPLE_OPACITY = 70
+ const val TONE_PERCENT = 95f
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
index 87b2528..f8785fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
@@ -33,14 +33,14 @@
private var isStarted: Boolean
init {
- setupShader(RippleShader.RippleShape.ELLIPSE)
+ setupShader(RippleShader.RippleShape.CIRCLE)
setRippleFill(true)
setSparkleStrength(0f)
- duration = 3000L
isStarted = false
}
fun expandRipple(onAnimationEnd: Runnable? = null) {
+ duration = DEFAULT_DURATION
isStarted = true
super.startRipple(onAnimationEnd)
}
@@ -50,6 +50,7 @@
if (!isStarted) {
return // Ignore if ripple is not started yet.
}
+ duration = DEFAULT_DURATION
// Reset all listeners to animator.
animator.removeAllListeners()
animator.addListener(object : AnimatorListenerAdapter() {
@@ -74,6 +75,7 @@
setRippleFill(false)
val startingPercentage = calculateStartingPercentage(newHeight)
+ animator.duration = EXPAND_TO_FULL_DURATION
animator.addUpdateListener { updateListener ->
val now = updateListener.currentPlayTime
val progress = updateListener.animatedValue as Float
@@ -100,4 +102,9 @@
val remainingPercentage = (1 - ratio).toDouble().pow(1 / 3.toDouble()).toFloat()
return 1 - remainingPercentage
}
+
+ companion object {
+ const val DEFAULT_DURATION = 333L
+ const val EXPAND_TO_FULL_DURATION = 1000L
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 1d86343..1edb837 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -24,9 +24,11 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.media.MediaProjectionAppSelectorActivity
import com.android.systemui.media.MediaProjectionAppSelectorActivity.Companion.EXTRA_HOST_APP_USER_HANDLE
+import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader
import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
@@ -43,7 +45,6 @@
import dagger.Subcomponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
-import java.lang.IllegalArgumentException
import javax.inject.Qualifier
import javax.inject.Scope
import kotlinx.coroutines.CoroutineScope
@@ -69,9 +70,10 @@
): Activity
}
-/** Scoped values for [MediaProjectionAppSelectorComponent].
- * We create a scope for the activity so certain dependencies like [TaskPreviewSizeProvider]
- * could be reused. */
+/**
+ * Scoped values for [MediaProjectionAppSelectorComponent]. We create a scope for the activity so
+ * certain dependencies like [TaskPreviewSizeProvider] could be reused.
+ */
@Module
interface MediaProjectionAppSelectorModule {
@@ -83,6 +85,10 @@
@Binds
@MediaProjectionAppSelectorScope
+ fun bindRecentTaskLabelLoader(impl: ActivityTaskManagerLabelLoader): RecentTaskLabelLoader
+
+ @Binds
+ @MediaProjectionAppSelectorScope
fun bindRecentTaskListProvider(impl: ShellRecentTaskListProvider): RecentTaskListProvider
@Binds
@@ -125,8 +131,10 @@
activity.intent.extras
?: error("MediaProjectionAppSelectorActivity should be launched with extras")
return extras.getParcelable(EXTRA_HOST_APP_USER_HANDLE)
- ?: error("MediaProjectionAppSelectorActivity should be provided with " +
- "$EXTRA_HOST_APP_USER_HANDLE extra")
+ ?: error(
+ "MediaProjectionAppSelectorActivity should be provided with " +
+ "$EXTRA_HOST_APP_USER_HANDLE extra"
+ )
}
@Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context)
@@ -146,9 +154,7 @@
/** Generates [MediaProjectionAppSelectorComponent]. */
@Subcomponent.Factory
interface Factory {
- /**
- * Create a factory to inject the activity into the graph
- */
+ /** Create a factory to inject the activity into the graph */
fun create(
@BindsInstance activity: MediaProjectionAppSelectorActivity,
@BindsInstance view: MediaProjectionAppSelectorView,
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt
new file mode 100644
index 0000000..eadcb93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector.data
+
+import android.annotation.UserIdInt
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+interface RecentTaskLabelLoader {
+ suspend fun loadLabel(userId: Int, componentName: ComponentName): CharSequence?
+}
+
+class ActivityTaskManagerLabelLoader
+@Inject
+constructor(
+ @Background private val coroutineDispatcher: CoroutineDispatcher,
+ private val packageManager: PackageManager
+) : RecentTaskLabelLoader {
+
+ override suspend fun loadLabel(
+ @UserIdInt userId: Int,
+ componentName: ComponentName
+ ): CharSequence? =
+ withContext(coroutineDispatcher) {
+ val userHandle = UserHandle(userId)
+ val appInfo =
+ packageManager.getApplicationInfo(
+ componentName.packageName,
+ PackageManager.ApplicationInfoFlags.of(0 /* no flags */)
+ )
+ val label = packageManager.getApplicationLabel(appInfo)
+ return@withContext packageManager.getUserBadgedLabel(label, userHandle)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
index 15cfeee..64f97f2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
@@ -20,11 +20,12 @@
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.android.systemui.R
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelector
import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
import com.android.systemui.mediaprojection.appselector.data.RecentTask
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader
import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import dagger.assisted.Assisted
@@ -40,9 +41,10 @@
@Assisted private val root: ViewGroup,
private val iconLoader: AppIconLoader,
private val thumbnailLoader: RecentTaskThumbnailLoader,
+ private val labelLoader: RecentTaskLabelLoader,
private val taskViewSizeProvider: TaskPreviewSizeProvider,
@MediaProjectionAppSelector private val scope: CoroutineScope
-) : RecyclerView.ViewHolder(root), ConfigurationListener, TaskPreviewSizeProvider.TaskPreviewSizeListener {
+) : ViewHolder(root), ConfigurationListener, TaskPreviewSizeProvider.TaskPreviewSizeListener {
val thumbnailView: MediaProjectionTaskView = root.requireViewById(R.id.task_thumbnail)
private val iconView: ImageView = root.requireViewById(R.id.task_icon)
@@ -64,6 +66,10 @@
val icon = iconLoader.loadIcon(task.userId, component)
iconView.setImageDrawable(icon)
}
+ launch {
+ val label = labelLoader.loadLabel(task.userId, component)
+ root.contentDescription = label
+ }
}
launch {
val thumbnail = thumbnailLoader.loadThumbnail(task.taskId)
@@ -88,10 +94,10 @@
private fun updateThumbnailSize() {
thumbnailView.layoutParams =
- thumbnailView.layoutParams.apply {
- width = taskViewSizeProvider.size.width()
- height = taskViewSizeProvider.size.height()
- }
+ thumbnailView.layoutParams.apply {
+ width = taskViewSizeProvider.size.width()
+ height = taskViewSizeProvider.size.height()
+ }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index c335a6d..5ea1c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -59,11 +59,11 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null) {
try {
- overviewProxy.onOverviewShown(triggeredFromAltTab, forward);
+ overviewProxy.onOverviewShown(triggeredFromAltTab);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send overview show event to launcher.", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1151475..dd7ea76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -30,6 +30,7 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -652,13 +653,14 @@
}
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
- boolean bouncerShowing, boolean isDozing, boolean panelExpanded) {
+ boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
keyguardShowing && !keyguardOccluded)
.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
keyguardShowing && keyguardOccluded)
.setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
.setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
+ .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming)
.commitUpdate(mContext.getDisplayId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 95d6c18..b041f95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -65,14 +65,14 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
return;
}
- mImpl.showRecentApps(triggeredFromAltTab, forward);
+ mImpl.showRecentApps(triggeredFromAltTab);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 010ceda..8848dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -31,7 +31,7 @@
default void preloadRecentApps() {}
default void cancelPreloadRecentApps() {}
- default void showRecentApps(boolean triggeredFromAltTab, boolean forward) {}
+ default void showRecentApps(boolean triggeredFromAltTab) {}
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
default void toggleRecentApps() {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index 017e57f..310baaf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -25,8 +25,22 @@
import com.android.systemui.R
object ActionIntentCreator {
+ /** @return a chooser intent to share the given URI. */
+ fun createShareIntent(uri: Uri) = createShareIntent(uri, null, null)
+
/** @return a chooser intent to share the given URI with the optional provided subject. */
- fun createShareIntent(uri: Uri, subject: String?): Intent {
+ fun createShareIntentWithSubject(uri: Uri, subject: String?) =
+ createShareIntent(uri, subject = subject)
+
+ /** @return a chooser intent to share the given URI with the optional provided extra text. */
+ fun createShareIntentWithExtraText(uri: Uri, extraText: String?) =
+ createShareIntent(uri, extraText = extraText)
+
+ private fun createShareIntent(
+ uri: Uri,
+ subject: String? = null,
+ extraText: String? = null
+ ): Intent {
// Create a share intent, this will always go through the chooser activity first
// which should not trigger auto-enter PiP
val sharingIntent =
@@ -43,6 +57,7 @@
)
putExtra(Intent.EXTRA_SUBJECT, subject)
+ putExtra(Intent.EXTRA_TEXT, extraText)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java
new file mode 100644
index 0000000..ab8fc65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.IAssistDataReceiver;
+import android.app.assist.AssistContent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Can be used to request the AssistContent from a provided task id, useful for getting the web uri
+ * if provided from the task.
+ *
+ * Forked from
+ * packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
+ */
+@SysUISingleton
+public class AssistContentRequester {
+ private static final String TAG = "AssistContentRequester";
+ private static final String ASSIST_KEY_CONTENT = "content";
+
+ /** For receiving content, called on the main thread. */
+ public interface Callback {
+ /**
+ * Called when the {@link android.app.assist.AssistContent} of the requested task is
+ * available.
+ **/
+ void onAssistContentAvailable(AssistContent assistContent);
+ }
+
+ private final IActivityTaskManager mActivityTaskManager;
+ private final String mPackageName;
+ private final Executor mCallbackExecutor;
+ private final Executor mSystemInteractionExecutor;
+ private final String mAttributionTag;
+
+ // If system loses the callback, our internal cache of original callback will also get cleared.
+ private final Map<Object, Callback> mPendingCallbacks =
+ Collections.synchronizedMap(new WeakHashMap<>());
+
+ @Inject
+ public AssistContentRequester(Context context, @Main Executor mainExecutor,
+ @Background Executor bgExecutor) {
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mPackageName = context.getApplicationContext().getPackageName();
+ mCallbackExecutor = mainExecutor;
+ mSystemInteractionExecutor = bgExecutor;
+ mAttributionTag = context.getAttributionTag();
+ }
+
+ /**
+ * Request the {@link AssistContent} from the task with the provided id.
+ *
+ * @param taskId to query for the content.
+ * @param callback to call when the content is available, called on the main thread.
+ */
+ public void requestAssistContent(final int taskId, final Callback callback) {
+ // ActivityTaskManager interaction here is synchronous, so call off the main thread.
+ mSystemInteractionExecutor.execute(() -> {
+ try {
+ mActivityTaskManager.requestAssistDataForTask(
+ new AssistDataReceiver(callback, this), taskId, mPackageName,
+ mAttributionTag);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
+ }
+ });
+ }
+
+ private void executeOnMainExecutor(Runnable callback) {
+ mCallbackExecutor.execute(callback);
+ }
+
+ private static final class AssistDataReceiver extends IAssistDataReceiver.Stub {
+
+ // The AssistDataReceiver binder callback object is passed to a system server, that may
+ // keep hold of it for longer than the lifetime of the AssistContentRequester object,
+ // potentially causing a memory leak. In the callback passed to the system server, only
+ // keep a weak reference to the parent object and lookup its callback if it still exists.
+ private final WeakReference<AssistContentRequester> mParentRef;
+ private final Object mCallbackKey = new Object();
+
+ AssistDataReceiver(Callback callback, AssistContentRequester parent) {
+ parent.mPendingCallbacks.put(mCallbackKey, callback);
+ mParentRef = new WeakReference<>(parent);
+ }
+
+ @Override
+ public void onHandleAssistData(Bundle data) {
+ if (data == null) {
+ return;
+ }
+
+ final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
+ if (content == null) {
+ Log.e(TAG, "Received AssistData, but no AssistContent found");
+ return;
+ }
+
+ AssistContentRequester requester = mParentRef.get();
+ if (requester != null) {
+ Callback callback = requester.mPendingCallbacks.get(mCallbackKey);
+ if (callback != null) {
+ requester.executeOnMainExecutor(
+ () -> callback.onAssistContentAvailable(content));
+ } else {
+ Log.d(TAG, "Callback received after calling UI was disposed of");
+ }
+ } else {
+ Log.d(TAG, "Callback received after Requester was collected");
+ }
+ }
+
+ @Override
+ public void onHandleAssistScreenshot(Bitmap screenshot) {}
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index d64b33b..ca8e101 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -366,7 +366,7 @@
private void doShare(Uri uri) {
if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri, null);
+ Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
mActionExecutor.launchIntentAsync(shareIntent, null,
mScreenshotUserHandle.getIdentifier(), false);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index f011aab..4db48ac 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -45,6 +45,7 @@
*
* @param request the request to process
*/
+ // TODO: Delete once SCREENSHOT_METADATA flag is launched
suspend fun process(request: ScreenshotRequest): ScreenshotRequest {
var result = request
@@ -93,12 +94,67 @@
* @param request the request to process
* @param callback the callback to provide the processed request, invoked from the main thread
*/
+ // TODO: Delete once SCREENSHOT_METADATA flag is launched
fun processAsync(request: ScreenshotRequest, callback: Consumer<ScreenshotRequest>) {
mainScope.launch {
val result = process(request)
callback.accept(result)
}
}
+
+ /**
+ * Inspects the incoming ScreenshotData, potentially modifying it based upon policy.
+ *
+ * @param screenshot the screenshot to process
+ */
+ suspend fun process(screenshot: ScreenshotData): ScreenshotData {
+ var result = screenshot
+
+ // Apply work profile screenshots policy:
+ //
+ // If the focused app belongs to a work profile, transforms a full screen
+ // (or partial) screenshot request to a task snapshot (provided image) screenshot.
+
+ // Whenever displayContentInfo is fetched, the topComponent is also populated
+ // regardless of the managed profile status.
+
+ if (screenshot.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
+ flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+ ) {
+ val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
+ Log.d(TAG, "findPrimaryContent: $info")
+ result.taskId = info.taskId
+ result.topComponent = info.component
+ result.userHandle = info.user
+
+ if (policy.isManagedProfile(info.user.identifier)) {
+ val image = capture.captureTask(info.taskId)
+ ?: error("Task snapshot returned a null Bitmap!")
+
+ // Provide the task snapshot as the screenshot
+ result.type = TAKE_SCREENSHOT_PROVIDED_IMAGE
+ result.bitmap = image
+ result.screenBounds = info.bounds
+ }
+ }
+
+ return result
+ }
+
+ /**
+ * Note: This is for compatibility with existing Java. Prefer the suspending function when
+ * calling from a Coroutine context.
+ *
+ * @param screenshot the screenshot to process
+ * @param callback the callback to provide the processed screenshot, invoked from the main
+ * thread
+ */
+ fun processAsync(screenshot: ScreenshotData, callback: Consumer<ScreenshotData>) {
+ mainScope.launch {
+ val result = process(screenshot)
+ callback.accept(result)
+ }
+ }
}
private const val TAG = "RequestProcessor"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 6d87922..adff6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -44,6 +44,7 @@
import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks;
import android.app.ICompatCameraControlCallback;
import android.app.Notification;
+import android.app.assist.AssistContent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -281,6 +282,7 @@
private final ActionIntentExecutor mActionExecutor;
private final UserManager mUserManager;
private final WorkProfileMessageController mWorkProfileMessageController;
+ private final AssistContentRequester mAssistContentRequester;
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
if (DEBUG_INPUT) {
@@ -328,7 +330,8 @@
ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
ActionIntentExecutor actionExecutor,
UserManager userManager,
- WorkProfileMessageController workProfileMessageController
+ WorkProfileMessageController workProfileMessageController,
+ AssistContentRequester assistContentRequester
) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
@@ -361,6 +364,7 @@
mActionExecutor = actionExecutor;
mUserManager = userManager;
mWorkProfileMessageController = workProfileMessageController;
+ mAssistContentRequester = assistContentRequester;
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
@@ -390,16 +394,142 @@
ClipboardOverlayController.SELF_PERMISSION, null, Context.RECEIVER_NOT_EXPORTED);
}
+ void handleScreenshot(ScreenshotData screenshot, Consumer<Uri> finisher,
+ RequestCallback requestCallback) {
+ Assert.isMainThread();
+ mCurrentRequestCallback = requestCallback;
+ if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) {
+ Rect bounds = getFullScreenRect();
+ screenshot.setBitmap(mImageCapture.captureDisplay(DEFAULT_DISPLAY, bounds));
+ screenshot.setScreenBounds(bounds);
+ }
+
+ if (screenshot.getBitmap() == null) {
+ Log.e(TAG, "handleScreenshot: Screenshot bitmap was null");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_capture_text);
+ if (mCurrentRequestCallback != null) {
+ mCurrentRequestCallback.reportError();
+ }
+ return;
+ }
+
+ if (!isUserSetupComplete(Process.myUserHandle())) {
+ Log.w(TAG, "User setup not complete, displaying toast only");
+ // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
+ // and sharing shouldn't be exposed to the user.
+ saveScreenshotAndToast(screenshot.getUserHandle(), finisher);
+ return;
+ }
+
+ mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
+ ClipboardOverlayController.SELF_PERMISSION);
+
+ mScreenshotTakenInPortrait =
+ mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
+
+ String oldPackageName = mPackageName;
+ mPackageName = screenshot.getPackageNameString();
+
+ mScreenBitmap = screenshot.getBitmap();
+ // Optimizations
+ mScreenBitmap.setHasAlpha(false);
+ mScreenBitmap.prepareToDraw();
+
+ prepareViewForNewScreenshot(screenshot, oldPackageName);
+
+ saveScreenshotInWorkerThread(screenshot.getUserHandle(), finisher,
+ this::showUiOnActionsReady, this::showUiOnQuickShareActionReady);
+
+ // The window is focusable by default
+ setWindowFocusable(true);
+ mScreenshotView.requestFocus();
+
+ enqueueScrollCaptureRequest(screenshot.getUserHandle());
+
+ attachWindow();
+
+ boolean showFlash = true;
+ if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ if (screenshot.getScreenBounds() != null
+ && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(),
+ screenshot.getScreenBounds())) {
+ showFlash = false;
+ } else {
+ showFlash = true;
+ screenshot.setInsets(Insets.NONE);
+ screenshot.setScreenBounds(new Rect(0, 0, screenshot.getBitmap().getWidth(),
+ screenshot.getBitmap().getHeight()));
+ }
+ }
+
+ prepareAnimation(screenshot.getScreenBounds(), showFlash);
+
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
+ mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
+ mContext.getDrawable(R.drawable.overlay_badge_background),
+ screenshot.getUserHandle()));
+ }
+ mScreenshotView.setScreenshot(screenshot);
+
+ if (screenshot.getTaskId() >= 0) {
+ mAssistContentRequester.requestAssistContent(screenshot.getTaskId(),
+ new AssistContentRequester.Callback() {
+ @Override
+ public void onAssistContentAvailable(AssistContent assistContent) {
+ screenshot.setContextUrl(assistContent.getWebUri());
+ }
+ });
+ }
+
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "setContentView: " + mScreenshotView);
+ }
+ setContentView(mScreenshotView);
+ // ignore system bar insets for the purpose of window layout
+ mWindow.getDecorView().setOnApplyWindowInsetsListener(
+ (v, insets) -> WindowInsets.CONSUMED);
+ mScreenshotHandler.cancelTimeout(); // restarted after animation
+ }
+
+ void prepareViewForNewScreenshot(ScreenshotData screenshot, String oldPackageName) {
+ withWindowAttached(() -> {
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+ && mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
+ mScreenshotView.announceForAccessibility(mContext.getResources().getString(
+ R.string.screenshot_saving_work_profile_title));
+ } else {
+ mScreenshotView.announceForAccessibility(
+ mContext.getResources().getString(R.string.screenshot_saving_title));
+ }
+ });
+
+ mScreenshotView.reset();
+
+ if (mScreenshotView.isAttachedToWindow()) {
+ // if we didn't already dismiss for another reason
+ if (!mScreenshotView.isDismissing()) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0,
+ oldPackageName);
+ }
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. "
+ + "(dismissing=" + mScreenshotView.isDismissing() + ")");
+ }
+ }
+
+ mScreenshotView.setPackageName(mPackageName);
+
+ mScreenshotView.updateOrientation(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets());
+ }
+
@MainThread
void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher,
RequestCallback requestCallback) {
Assert.isMainThread();
mCurrentRequestCallback = requestCallback;
- DisplayMetrics displayMetrics = new DisplayMetrics();
- getDefaultDisplay().getRealMetrics(displayMetrics);
- takeScreenshotInternal(
- topComponent, finisher,
- new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
+ takeScreenshotInternal(topComponent, finisher, getFullScreenRect());
}
@MainThread
@@ -641,6 +771,42 @@
setWindowFocusable(true);
mScreenshotView.requestFocus();
+ enqueueScrollCaptureRequest(owner);
+
+ attachWindow();
+ prepareAnimation(screenRect, showFlash);
+
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
+ mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
+ mContext.getDrawable(R.drawable.overlay_badge_background), owner));
+ }
+ mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "setContentView: " + mScreenshotView);
+ }
+ setContentView(mScreenshotView);
+ // ignore system bar insets for the purpose of window layout
+ mWindow.getDecorView().setOnApplyWindowInsetsListener(
+ (v, insets) -> WindowInsets.CONSUMED);
+ mScreenshotHandler.cancelTimeout(); // restarted after animation
+ }
+
+ private void prepareAnimation(Rect screenRect, boolean showFlash) {
+ mScreenshotView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "onPreDraw: startAnimation");
+ }
+ mScreenshotView.getViewTreeObserver().removeOnPreDrawListener(this);
+ startAnimation(screenRect, showFlash);
+ return true;
+ }
+ });
+ }
+
+ private void enqueueScrollCaptureRequest(UserHandle owner) {
// Wait until this window is attached to request because it is
// the reference used to locate the target window (below).
withWindowAttached(() -> {
@@ -678,30 +844,6 @@
}
});
});
-
- attachWindow();
- mScreenshotView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (DEBUG_WINDOW) {
- Log.d(TAG, "onPreDraw: startAnimation");
- }
- mScreenshotView.getViewTreeObserver().removeOnPreDrawListener(this);
- startAnimation(screenRect, showFlash);
- return true;
- }
- });
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
- mContext.getDrawable(R.drawable.overlay_badge_background), owner));
- }
- mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
-
- // ignore system bar insets for the purpose of window layout
- mWindow.getDecorView().setOnApplyWindowInsetsListener(
- (v, insets) -> WindowInsets.CONSUMED);
- mScreenshotHandler.cancelTimeout(); // restarted after animation
}
private void requestScrollCapture(UserHandle owner) {
@@ -1154,6 +1296,12 @@
return !mIsLowRamDevice;
}
+ private Rect getFullScreenRect() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getDefaultDisplay().getRealMetrics(displayMetrics);
+ return new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ }
+
/** Does the aspect ratio of the bitmap with insets removed match the bounds. */
private static boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets,
Rect screenBounds) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
new file mode 100644
index 0000000..c43e4b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
@@ -0,0 +1,46 @@
+package com.android.systemui.screenshot
+
+import android.content.ComponentName
+import android.graphics.Bitmap
+import android.graphics.Insets
+import android.graphics.Rect
+import android.net.Uri
+import android.os.UserHandle
+import android.view.WindowManager.ScreenshotSource
+import android.view.WindowManager.ScreenshotType
+import com.android.internal.util.ScreenshotRequest
+
+/** ScreenshotData represents the current state of a single screenshot being acquired. */
+data class ScreenshotData(
+ @ScreenshotType var type: Int,
+ @ScreenshotSource var source: Int,
+ /** UserHandle for the owner of the app being screenshotted, if known. */
+ var userHandle: UserHandle?,
+ /** ComponentName of the top-most app in the screenshot. */
+ var topComponent: ComponentName?,
+ var screenBounds: Rect?,
+ var taskId: Int,
+ var insets: Insets,
+ var bitmap: Bitmap?,
+ /** App-provided URL representing the content the user was looking at in the screenshot. */
+ var contextUrl: Uri? = null,
+) {
+ val packageNameString: String
+ get() = if (topComponent == null) "" else topComponent!!.packageName
+
+ companion object {
+ @JvmStatic
+ fun fromRequest(request: ScreenshotRequest): ScreenshotData {
+ return ScreenshotData(
+ request.type,
+ request.source,
+ if (request.userId >= 0) UserHandle.of(request.userId) else null,
+ request.topComponent,
+ request.boundsInScreen,
+ request.taskId,
+ request.insets,
+ request.bitmap,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 7c013a8..bd4ea11 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -39,6 +39,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -168,6 +169,8 @@
private final ArrayList<OverlayActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
+ // Should only be set/used if the SCREENSHOT_METADATA flag is set.
+ private ScreenshotData mScreenshotData;
private final InteractionJankMonitor mInteractionJankMonitor;
private long mDefaultTimeoutOfTimeoutHandler;
@@ -477,6 +480,13 @@
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
}
+ void setScreenshot(ScreenshotData screenshot) {
+ mScreenshotData = screenshot;
+ setScreenshot(screenshot.getBitmap(), screenshot.getInsets());
+ mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, screenshot.getBitmap(),
+ screenshot.getInsets()));
+ }
+
void setPackageName(String packageName) {
mPackageName = packageName;
}
@@ -815,9 +825,17 @@
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
prepareSharedTransition();
- mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createShareIntent(
- imageData.uri, imageData.subject),
+
+ Intent shareIntent;
+ if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
+ && mScreenshotData.getContextUrl() != null) {
+ shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithExtraText(
+ imageData.uri, mScreenshotData.getContextUrl().toString());
+ } else {
+ shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithSubject(
+ imageData.uri, imageData.subject);
+ }
+ mActionExecutor.launchIntentAsync(shareIntent,
imageData.shareTransition.get().bundle,
imageData.owner.getIdentifier(), false);
} else {
@@ -1119,6 +1137,7 @@
mQuickShareChip = null;
setAlpha(1);
mScreenshotStatic.setAlpha(1);
+ mScreenshotData = null;
}
private void startSharedTransition(ActionTransition transition) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 7b271a8..4214c8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -59,6 +59,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagListenable.FlagEvent;
+import com.android.systemui.flags.Flags;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -221,8 +222,33 @@
return;
}
- mProcessor.processAsync(request,
- (r) -> dispatchToController(r, onSaved, callback));
+ if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_METADATA)) {
+ Log.d(TAG, "Processing screenshot data");
+ ScreenshotData screenshotData = ScreenshotData.fromRequest(request);
+ mProcessor.processAsync(screenshotData,
+ (data) -> dispatchToController(data, onSaved, callback));
+ } else {
+ mProcessor.processAsync(request,
+ (r) -> dispatchToController(r, onSaved, callback));
+ }
+ }
+
+ private void dispatchToController(ScreenshotData screenshot,
+ Consumer<Uri> uriConsumer, RequestCallback callback) {
+
+ mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshot.getSource()), 0,
+ screenshot.getPackageNameString());
+
+ if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
+ && screenshot.getBitmap() == null) {
+ Log.e(TAG, "Got null bitmap from screenshot message");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_capture_text);
+ callback.reportError();
+ return;
+ }
+
+ mScreenshot.handleScreenshot(screenshot, uriConsumer, callback);
}
private void dispatchToController(ScreenshotRequest request,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index b532c13..d11f9da 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2097,7 +2097,17 @@
}
}
- public void expandWithoutQs() {
+ /**
+ * Expand shade so that notifications are visible.
+ * Non-split shade: just expanding shade or collapsing QS when they're expanded.
+ * Split shade: only expanding shade, notifications are always visible
+ *
+ * Called when `adb shell cmd statusbar expand-notifications` is executed.
+ */
+ public void expandShadeToNotifications() {
+ if (mSplitShadeEnabled && (isShadeFullyOpen() || isExpanding())) {
+ return;
+ }
if (isQsExpanded()) {
flingSettings(0 /* velocity */, FLING_COLLAPSE);
} else {
@@ -5536,7 +5546,7 @@
@Override
public void flingTopOverscroll(float velocity, boolean open) {
- // in split shade mode we want to expand/collapse QS only when touch happens within QS
+ // in split shade touches affect QS only when touch happens within QS
if (isSplitShadeAndTouchXOutsideQs(mInitialTouchX)) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index ab2e692..156e4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -563,7 +563,8 @@
mCurrentState.keyguardOccluded,
mCurrentState.bouncerShowing,
mCurrentState.dozing,
- mCurrentState.panelExpanded);
+ mCurrentState.panelExpanded,
+ mCurrentState.dreaming);
}
}
@@ -778,6 +779,12 @@
}
@Override
+ public void setDreaming(boolean dreaming) {
+ mCurrentState.dreaming = dreaming;
+ apply(mCurrentState);
+ }
+
+ @Override
public void setForcePluginOpen(boolean forceOpen, Object token) {
if (forceOpen) {
mCurrentState.forceOpenTokens.add(token);
@@ -904,5 +911,10 @@
public void onDozingChanged(boolean isDozing) {
setDozing(isDozing);
}
+
+ @Override
+ public void onDreamingChanged(boolean isDreaming) {
+ setDreaming(isDreaming);
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
index 736404aa..fed9b84 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -23,8 +23,8 @@
import com.android.systemui.statusbar.StatusBarState
/**
- * Represents state of shade window, used by [NotificationShadeWindowControllerImpl].
- * Contains nested class [Buffer] for pretty table logging in bug reports.
+ * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. Contains
+ * nested class [Buffer] for pretty table logging in bug reports.
*/
class NotificationShadeWindowState(
@JvmField var keyguardShowing: Boolean = false,
@@ -55,6 +55,7 @@
@JvmField var remoteInputActive: Boolean = false,
@JvmField var forcePluginOpen: Boolean = false,
@JvmField var dozing: Boolean = false,
+ @JvmField var dreaming: Boolean = false,
@JvmField var scrimsVisibility: Int = 0,
@JvmField var backgroundBlurRadius: Int = 0,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt b/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
index 1302ec9..88e8ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
@@ -15,8 +15,6 @@
*/
package com.android.systemui.smartspace.preconditions
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.util.concurrency.Execution
@@ -24,11 +22,9 @@
/**
* {@link LockscreenPrecondition} covers the conditions that must be met before Smartspace can be
- * used over lockscreen. These conditions include the device being provisioned with a setup user
- * and the Smartspace feature flag enabled.
+ * used over lockscreen. These conditions include the device being provisioned with a setup user.
*/
class LockscreenPrecondition @Inject constructor(
- private val featureFlags: FeatureFlags,
private val deviceProvisionedController: DeviceProvisionedController,
private val execution: Execution
) : SmartspacePrecondition {
@@ -90,6 +86,6 @@
override fun conditionsMet(): Boolean {
execution.assertIsMainThread()
- return featureFlags.isEnabled(Flags.SMARTSPACE) && deviceReady
+ return deviceReady
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 7556750..a0a7586 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -53,7 +53,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
@@ -228,7 +227,7 @@
*/
default void setImeWindowStatus(int displayId, IBinder token, int vis,
@BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
- default void showRecentApps(boolean triggeredFromAltTab, boolean forward) { }
+ default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleRecentApps() { }
default void toggleSplitScreen() { }
@@ -695,11 +694,11 @@
}
}
- public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
- mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0,
- forward ? 1 : 0, null).sendToTarget();
+ mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0, 0,
+ null).sendToTarget();
}
}
@@ -1271,8 +1270,7 @@
public void showMediaOutputSwitcher(String packageName) {
int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
- Slog.e(TAG, "Call only allowed from system server.");
- return;
+ throw new SecurityException("Call only allowed from system server.");
}
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
@@ -1407,7 +1405,7 @@
break;
case MSG_SHOW_RECENT_APPS:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ mCallbacks.get(i).showRecentApps(msg.arg1 != 0);
}
break;
case MSG_HIDE_RECENT_APPS:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 0b1807d..2ca0b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -143,6 +143,9 @@
/** Sets the state of whether sysui is dozing or not. */
default void setDozing(boolean dozing) {}
+ /** Sets the state of whether sysui is dreaming or not. */
+ default void setDreaming(boolean dreaming) {}
+
/** Sets the state of whether plugin open is forced or not. */
default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 58ce447..b9ac918 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -128,6 +128,11 @@
private boolean mIsDozing;
/**
+ * If the device is currently dreaming or not.
+ */
+ private boolean mIsDreaming;
+
+ /**
* If the status bar is currently expanded or not.
*/
private boolean mIsExpanded;
@@ -293,6 +298,29 @@
}
@Override
+ public boolean setIsDreaming(boolean isDreaming) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "setIsDreaming:" + isDreaming);
+ }
+ if (mIsDreaming == isDreaming) {
+ return false;
+ }
+
+ mIsDreaming = isDreaming;
+
+ synchronized (mListeners) {
+ String tag = getClass().getSimpleName() + "#setIsDreaming";
+ DejankUtils.startDetectingBlockingIpcs(tag);
+ for (RankedListener rl : new ArrayList<>(mListeners)) {
+ rl.mListener.onDreamingChanged(isDreaming);
+ }
+ DejankUtils.stopDetectingBlockingIpcs(tag);
+ }
+
+ return true;
+ }
+
+ @Override
public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
if (animated && mDozeAmountTarget == dozeAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 5a392a9..4043fce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -99,6 +99,13 @@
boolean setIsDozing(boolean isDozing);
/**
+ * Update the dreaming state from {@link CentralSurfaces}'s perspective
+ * @param isDreaming whether we are dreaming
+ * @return {@code true} if the state changed, else {@code false}
+ */
+ boolean setIsDreaming(boolean isDreaming);
+
+ /**
* Changes the current doze amount, also starts the
* {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 9a65e34..098c617 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -25,12 +25,15 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.AnimationFeatureFlags;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpHandler;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
@@ -281,7 +284,8 @@
static DialogLaunchAnimator provideDialogLaunchAnimator(IDreamManager dreamManager,
KeyguardStateController keyguardStateController,
Lazy<AlternateBouncerInteractor> alternateBouncerInteractor,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ AnimationFeatureFlags animationFeatureFlags) {
DialogLaunchAnimator.Callback callback = new DialogLaunchAnimator.Callback() {
@Override
public boolean isDreaming() {
@@ -303,6 +307,19 @@
return alternateBouncerInteractor.get().canShowAlternateBouncerForFingerprint();
}
};
- return new DialogLaunchAnimator(callback, interactionJankMonitor);
+ return new DialogLaunchAnimator(callback, interactionJankMonitor, animationFeatureFlags);
+ }
+
+ /**
+ */
+ @Provides
+ @SysUISingleton
+ static AnimationFeatureFlags provideAnimationFeatureFlags(FeatureFlags featureFlags) {
+ return new AnimationFeatureFlags() {
+ @Override
+ public boolean isPredictiveBackQsDialogAnim() {
+ return featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM);
+ }
+ };
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 803c282..daed286 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -100,7 +100,7 @@
private val regionSamplingEnabled =
featureFlags.isEnabled(Flags.REGION_SAMPLING)
-
+ private var isContentUpdatedOnce = false
private var showNotifications = false
private var showSensitiveContentForCurrentUser = false
private var showSensitiveContentForManagedUser = false
@@ -115,19 +115,6 @@
override fun onViewAttachedToWindow(v: View) {
smartspaceViews.add(v as SmartspaceView)
- if (regionSamplingEnabled) {
- var regionSampler = RegionSampler(
- v,
- uiExecutor,
- bgExecutor,
- regionSamplingEnabled,
- updateFun
- )
- initializeTextColors(regionSampler)
- regionSampler.startRegionSampler()
- regionSamplers.put(v, regionSampler)
- }
-
connectSession()
updateTextColorFromWallpaper()
@@ -137,12 +124,6 @@
override fun onViewDetachedFromWindow(v: View) {
smartspaceViews.remove(v as SmartspaceView)
- if (regionSamplingEnabled) {
- var regionSampler = regionSamplers.getValue(v)
- regionSampler.stopRegionSampler()
- regionSamplers.remove(v)
- }
-
if (smartspaceViews.isEmpty()) {
disconnect()
}
@@ -153,6 +134,24 @@
execution.assertIsMainThread()
val filteredTargets = targets.filter(::filterSmartspaceTarget)
plugin?.onTargetsAvailable(filteredTargets)
+ if (!isContentUpdatedOnce) {
+ for (v in smartspaceViews) {
+ if (regionSamplingEnabled) {
+ var regionSampler = RegionSampler(
+ v as View,
+ uiExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ updateFun
+ )
+ initializeTextColors(regionSampler)
+ regionSamplers[v] = regionSampler
+ regionSampler.startRegionSampler()
+ }
+ updateTextColorFromWallpaper()
+ }
+ isContentUpdatedOnce = true
+ }
}
private val userTrackerCallback = object : UserTracker.Callback {
@@ -208,7 +207,7 @@
fun isEnabled(): Boolean {
execution.assertIsMainThread()
- return featureFlags.isEnabled(Flags.SMARTSPACE) && plugin != null
+ return plugin != null
}
private fun updateBypassEnabled() {
@@ -399,7 +398,8 @@
private fun updateTextColorFromWallpaper() {
val wallpaperManager = WallpaperManager.getInstance(context)
- if (!regionSamplingEnabled || wallpaperManager.lockScreenWallpaperExists()) {
+ if (!regionSamplingEnabled || wallpaperManager.lockScreenWallpaperExists() ||
+ regionSamplers.isEmpty()) {
val wallpaperTextColor =
Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 635ed7c..4856759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -32,8 +32,6 @@
fun isDevLoggingEnabled(): Boolean =
featureFlags.isEnabled(Flags.NOTIFICATION_PIPELINE_DEVELOPER_LOGGING)
- fun isSmartspaceDedupingEnabled(): Boolean = featureFlags.isEnabled(Flags.SMARTSPACE)
-
fun fullScreenIntentRequiresKeyguard(): Boolean =
featureFlags.isEnabled(Flags.FSI_REQUIRES_KEYGUARD)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index aeae89c..7e53d54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -31,6 +31,7 @@
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.KeyguardBypassController.OnBypassStateChangedListener
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
@@ -38,7 +39,6 @@
import javax.inject.Inject
import kotlin.math.min
-
@SysUISingleton
class NotificationWakeUpCoordinator @Inject constructor(
dumpManager: DumpManager,
@@ -68,6 +68,7 @@
private var mLinearDozeAmount: Float = 0.0f
private var mDozeAmount: Float = 0.0f
private var mDozeAmountSource: String = "init"
+ private var mNotifsHiddenByDozeAmountOverride: Boolean = false
private var mNotificationVisibleAmount = 0.0f
private var mNotificationsVisible = false
private var mNotificationsVisibleForExpansion = false
@@ -130,6 +131,7 @@
}
}
}
+
/**
* True if we can show pulsing heads up notifications
*/
@@ -149,10 +151,19 @@
return canShow
}
+ private val bypassStateChangedListener = object : OnBypassStateChangedListener {
+ override fun onBypassStateChanged(isEnabled: Boolean) {
+ // When the bypass state changes, we have to check whether we should re-show the
+ // notifications by clearing the doze amount override which hides them.
+ maybeClearDozeAmountOverrideHidingNotifs()
+ }
+ }
+
init {
dumpManager.registerDumpable(this)
mHeadsUpManager.addListener(this)
statusBarStateController.addCallback(this)
+ bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
addListener(object : WakeUpListener {
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
if (isFullyHidden && mNotificationsVisibleForExpansion) {
@@ -261,12 +272,18 @@
setDozeAmount(linear, eased, source = "StatusBar")
}
- fun setDozeAmount(linear: Float, eased: Float, source: String) {
+ fun setDozeAmount(
+ linear: Float,
+ eased: Float,
+ source: String,
+ hidesNotifsByOverride: Boolean = false
+ ) {
val changed = linear != mLinearDozeAmount
logger.logSetDozeAmount(linear, eased, source, statusBarStateController.state, changed)
mLinearDozeAmount = linear
mDozeAmount = eased
mDozeAmountSource = source
+ mNotifsHiddenByDozeAmountOverride = hidesNotifsByOverride
mStackScrollerController.setDozeAmount(mDozeAmount)
updateHideAmount()
if (changed && linear == 0.0f) {
@@ -295,6 +312,8 @@
return
}
+ maybeClearDozeAmountOverrideHidingNotifs()
+
if (bypassController.bypassEnabled &&
newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
(!statusBarStateController.isDozing || shouldAnimateVisibility())) {
@@ -325,7 +344,8 @@
private fun overrideDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)")
+ setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)",
+ hidesNotifsByOverride = true)
} else {
setDozeAmount(0f, 0f, source = "Override: bypass (shade)")
}
@@ -335,6 +355,37 @@
}
/**
+ * If the last [setDozeAmount] call was an override to hide notifications, then this call will
+ * check for the set of states that may have caused that override, and if none of them still
+ * apply, and the device is awake or not on the keyguard, then dozeAmount will be reset to 0.
+ * This fixes bugs where the bypass state changing could result in stale overrides, hiding
+ * notifications either on the inside screen or even after unlock.
+ */
+ private fun maybeClearDozeAmountOverrideHidingNotifs() {
+ if (mNotifsHiddenByDozeAmountOverride) {
+ val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD
+ val dozing = statusBarStateController.isDozing
+ val bypass = bypassController.bypassEnabled
+ val animating =
+ screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()
+ // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and
+ // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only
+ // clear the override if both those conditions are cleared. But also require either
+ // !dozing or !onKeyguard because those conditions should indicate that we intend
+ // notifications to be visible, and thus it is safe to unhide them.
+ val willRemove = (!onKeyguard || !dozing) && !bypass && !animating
+ logger.logMaybeClearDozeAmountOverrideHidingNotifs(
+ willRemove = willRemove,
+ onKeyguard = onKeyguard, dozing = dozing,
+ bypass = bypass, animating = animating,
+ )
+ if (willRemove) {
+ setDozeAmount(0f, 0f, source = "Removed: $mDozeAmountSource")
+ }
+ }
+ }
+
+ /**
* If we're playing the screen off animation, force the notification doze amount to be 1f (fully
* dozing). This is needed so that the notifications aren't briefly visible as the screen turns
* off and dozeAmount goes from 1f to 0f.
@@ -344,7 +395,8 @@
*/
private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean {
if (screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()) {
- setDozeAmount(1f, 1f, source = "Override: animating screen off")
+ setDozeAmount(1f, 1f, source = "Override: animating screen off",
+ hidesNotifsByOverride = true)
return true
}
@@ -430,6 +482,7 @@
pw.println("mLinearDozeAmount: $mLinearDozeAmount")
pw.println("mDozeAmount: $mDozeAmount")
pw.println("mDozeAmountSource: $mDozeAmountSource")
+ pw.println("mNotifsHiddenByDozeAmountOverride: $mNotifsHiddenByDozeAmountOverride")
pw.println("mNotificationVisibleAmount: $mNotificationVisibleAmount")
pw.println("mNotificationsVisible: $mNotificationsVisible")
pw.println("mNotificationsVisibleForExpansion: $mNotificationsVisibleForExpansion")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index de18b0c..4464531 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -46,6 +46,25 @@
)
}
+ fun logMaybeClearDozeAmountOverrideHidingNotifs(
+ willRemove: Boolean,
+ onKeyguard: Boolean,
+ dozing: Boolean,
+ bypass: Boolean,
+ animating: Boolean,
+ ) {
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 =
+ "willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" +
+ " bypass=$bypass animating=$animating"
+ },
+ { "maybeClearDozeAmountOverrideHidingNotifs() $str1" }
+ )
+ }
+
fun logOnDozeAmountChanged(linear: Float, eased: Float) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 76252d0..e996b78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -114,10 +114,10 @@
.onStart { emit(Unit) }
// for each change, lookup the new value
.map {
- secureSettings.getBoolForUser(
+ secureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
UserHandle.USER_CURRENT,
- )
+ ) == 1
}
// perform lookups on the bg thread pool
.flowOn(bgDispatcher)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 1399385..03a3ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -88,9 +88,7 @@
mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator)
mCoordinators.add(sensitiveContentCoordinator)
- if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
- mCoordinators.add(smartspaceDedupingCoordinator)
- }
+ mCoordinators.add(smartspaceDedupingCoordinator)
mCoordinators.add(headsUpCoordinator)
mCoordinators.add(gutsCoordinator)
mCoordinators.add(preparationCoordinator)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 66632e4..856d7de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -218,7 +218,7 @@
return;
}
- mNotificationPanelViewController.expandWithoutQs();
+ mNotificationPanelViewController.expandShadeToNotifications();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 001da6f..f7b8745 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1146,7 +1146,7 @@
if (hideImmediately) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
} else {
- mNotificationPanelViewController.expandWithoutQs();
+ mNotificationPanelViewController.expandShadeToNotifications();
}
}
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index ae48c2d3..50cce45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -17,5 +17,5 @@
public interface StatusBarWindowCallback {
void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
- boolean isDozing, boolean panelExpanded);
+ boolean isDozing, boolean panelExpanded, boolean isDreaming);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index f8c17e8..4866f73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -303,7 +303,8 @@
mEntry.mRemoteEditImeVisible = editTextRootWindowInsets != null
&& editTextRootWindowInsets.isVisible(WindowInsets.Type.ime());
if (!mEntry.mRemoteEditImeVisible && !mEditText.mShowImeOnInputConnection) {
- mController.removeRemoteInput(mEntry, mToken);
+ // Pass null to ensure all inputs are cleared for this entry b/227115380
+ mController.removeRemoteInput(mEntry, null);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
index 5a8850a..dde2a80 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
@@ -39,6 +39,17 @@
private val featureFlags: FeatureFlags,
) : CoreStartable, StylusManager.StylusCallback, StylusManager.StylusBatteryCallback {
+ override fun onStylusAdded(deviceId: Int) {
+ // On some devices, the addition of a new internal stylus indicates the use of a
+ // USI stylus with a different vendor/product ID. We would therefore like to reset
+ // the battery notification suppression, in case the user has dismissed a low battery
+ // notification of the previous stylus.
+ val device = inputManager.getInputDevice(deviceId) ?: return
+ if (!device.isExternal) {
+ stylusUsiPowerUi.updateSuppression(false)
+ }
+ }
+
override fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {
stylusUsiPowerUi.refresh()
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
index 8d5e01c..9050dad 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
@@ -29,13 +29,14 @@
import android.os.Handler
import android.os.UserHandle
import android.util.Log
-import android.view.InputDevice
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shared.hardware.hasInputDevice
+import com.android.systemui.shared.hardware.isAnyStylusSource
import com.android.systemui.util.NotificationChannels
import java.text.NumberFormat
import javax.inject.Inject
@@ -150,10 +151,7 @@
}
private fun hasConnectedBluetoothStylus(): Boolean {
- // TODO(b/257936830): get bt address once input api available
- return inputManager.inputDeviceIds.any { deviceId ->
- inputManager.getInputDevice(deviceId).supportsSource(InputDevice.SOURCE_STYLUS)
- }
+ return inputManager.hasInputDevice { it.isAnyStylusSource && it.bluetoothAddress != null }
}
private fun getPendingBroadcast(action: String): PendingIntent? {
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index 0b2f004..31f35fc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -1,15 +1,17 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.systemui.util.leak;
@@ -26,7 +28,27 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-public class RotationUtils {
+/**
+ * Utility class that provides device orientation.
+ *
+ * <p>Consider using {@link Surface.Rotation} or add a function that respects device aspect ratio
+ * and {@code android.internal.R.bool.config_reverseDefaultRotation}.
+ *
+ * <p>If you only care about the rotation, use {@link Surface.Rotation}, as it always gives the
+ * counter clock-wise rotation. (e.g. If you have a device that has a charging port at the bottom,
+ * rotating three times in counter clock direction will give you {@link Surface#ROTATION_270} while
+ * having the charging port on the left side of the device.)
+ *
+ * <p>If you need whether the device is in portrait or landscape (or their opposites), please add a
+ * function here that respects the device aspect ratio and
+ * {@code android.internal.R.bool.config_reverseDefaultRotation} together.
+ *
+ * <p>Note that {@code android.internal.R.bool.config_reverseDefaultRotation} does not change the
+ * winding order. In other words, the rotation order (counter clock-wise) will remain the same. It
+ * only flips the device orientation, such that portrait becomes upside down, landscape becomes
+ * seascape.
+ */
+public final class RotationUtils {
public static final int ROTATION_NONE = 0;
public static final int ROTATION_LANDSCAPE = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 7033ccd..5d896cb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -236,7 +236,8 @@
// Store callback in a field so it won't get GC'd
mStatusBarWindowCallback =
- (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) ->
+ (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded,
+ isDreaming) ->
mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index c76b127..00b2fbe 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -51,7 +51,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
@@ -140,8 +139,9 @@
@Test
fun themeChanged_verifyClockPaletteUpdated() = runBlocking(IMMEDIATE) {
- verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
- verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
+ // TODO(b/266103601): delete this test and add more coverage for updateColors()
+ // verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+ // verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
verify(configurationController).addCallback(capture(captor))
@@ -152,9 +152,6 @@
@Test
fun fontChanged_verifyFontSizeUpdated() = runBlocking(IMMEDIATE) {
- verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
- verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
-
val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
verify(configurationController).addCallback(capture(captor))
captor.value.onDensityOrFontScaleChanged()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
new file mode 100644
index 0000000..3bdbf97
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
@@ -0,0 +1,87 @@
+package com.android.systemui.animation.back
+
+import android.util.DisplayMetrics
+import android.window.BackEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+private data class BackInput(val progressX: Float, val progressY: Float, val edge: Int)
+
+@SmallTest
+@RunWith(JUnit4::class)
+class BackAnimationSpecTest : SysuiTestCase() {
+ private var displayMetrics =
+ DisplayMetrics().apply {
+ widthPixels = 100
+ heightPixels = 200
+ density = 3f
+ }
+
+ @Test
+ fun sysUi_floatingSystemSurfaces_animationValues() {
+ val maxX = 14.0f
+ val maxY = 4.0f
+ val minScale = 0.8f
+
+ val backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics)
+
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 0f, progressY = 0f, edge = BackEvent.EDGE_LEFT),
+ expected = BackTransformation(translateX = 0f, translateY = 0f, scale = 1f),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 1f, progressY = 0f, edge = BackEvent.EDGE_LEFT),
+ expected = BackTransformation(translateX = -maxX, translateY = 0f, scale = minScale),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 1f, progressY = 0f, edge = BackEvent.EDGE_RIGHT),
+ expected = BackTransformation(translateX = maxX, translateY = 0f, scale = minScale),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 1f, progressY = 1f, edge = BackEvent.EDGE_LEFT),
+ expected = BackTransformation(translateX = -maxX, translateY = -maxY, scale = minScale),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 0f, progressY = 1f, edge = BackEvent.EDGE_LEFT),
+ expected = BackTransformation(translateX = 0f, translateY = -maxY, scale = 1f),
+ )
+ assertBackTransformation(
+ backAnimationSpec = backAnimationSpec,
+ backInput = BackInput(progressX = 0f, progressY = -1f, edge = BackEvent.EDGE_LEFT),
+ expected = BackTransformation(translateX = 0f, translateY = maxY, scale = 1f),
+ )
+ }
+}
+
+private fun assertBackTransformation(
+ backAnimationSpec: BackAnimationSpec,
+ backInput: BackInput,
+ expected: BackTransformation,
+) {
+ val actual = BackTransformation()
+ backAnimationSpec.getBackTransformation(
+ backEvent =
+ BackEvent(
+ /* touchX = */ 0f,
+ /* touchY = */ 0f,
+ /* progress = */ backInput.progressX,
+ /* swipeEdge = */ backInput.edge,
+ ),
+ progressY = backInput.progressY,
+ result = actual
+ )
+
+ val tolerance = 0f
+ assertThat(actual.translateX).isWithin(tolerance).of(expected.translateX)
+ assertThat(actual.translateY).isWithin(tolerance).of(expected.translateY)
+ assertThat(actual.scale).isWithin(tolerance).of(expected.scale)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt
new file mode 100644
index 0000000..190b3d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt
@@ -0,0 +1,80 @@
+package com.android.systemui.animation.back
+
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+
+@SmallTest
+@RunWith(JUnit4::class)
+class BackTransformationTest : SysuiTestCase() {
+ private val targetView: View = mock()
+
+ @Test
+ fun defaultValue_noTransformation() {
+ val transformation = BackTransformation()
+
+ assertThat(transformation.translateX).isNaN()
+ assertThat(transformation.translateY).isNaN()
+ assertThat(transformation.scale).isNaN()
+ }
+
+ @Test
+ fun applyTo_targetView_translateX_Y_Scale() {
+ val transformation = BackTransformation(translateX = 0f, translateY = 0f, scale = 1f)
+
+ transformation.applyTo(targetView = targetView)
+
+ verify(targetView).translationX = 0f
+ verify(targetView).translationY = 0f
+ verify(targetView).scaleX = 1f
+ verify(targetView).scaleY = 1f
+ verifyNoMoreInteractions(targetView)
+ }
+
+ @Test
+ fun applyTo_targetView_translateX() {
+ val transformation = BackTransformation(translateX = 1f)
+
+ transformation.applyTo(targetView = targetView)
+
+ verify(targetView).translationX = 1f
+ verifyNoMoreInteractions(targetView)
+ }
+
+ @Test
+ fun applyTo_targetView_translateY() {
+ val transformation = BackTransformation(translateY = 2f)
+
+ transformation.applyTo(targetView = targetView)
+
+ verify(targetView).translationY = 2f
+ verifyNoMoreInteractions(targetView)
+ }
+
+ @Test
+ fun applyTo_targetView_scale() {
+ val transformation = BackTransformation(scale = 3f)
+
+ transformation.applyTo(targetView = targetView)
+
+ verify(targetView).scaleX = 3f
+ verify(targetView).scaleY = 3f
+ verifyNoMoreInteractions(targetView)
+ }
+
+ @Test
+ fun applyTo_targetView_noTransformation() {
+ val transformation = BackTransformation()
+
+ transformation.applyTo(targetView = targetView)
+
+ verifyNoMoreInteractions(targetView)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
new file mode 100644
index 0000000..921f9a8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
@@ -0,0 +1,63 @@
+package com.android.systemui.animation.back
+
+import android.util.DisplayMetrics
+import android.window.BackEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(JUnit4::class)
+class OnBackAnimationCallbackExtensionTest : SysuiTestCase() {
+ private val onBackProgress: (BackTransformation) -> Unit = mock()
+ private val onBackStart: (BackEvent) -> Unit = mock()
+ private val onBackInvoke: () -> Unit = mock()
+ private val onBackCancel: () -> Unit = mock()
+
+ private val displayMetrics =
+ DisplayMetrics().apply {
+ widthPixels = 100
+ heightPixels = 100
+ density = 1f
+ }
+
+ private val onBackAnimationCallback =
+ onBackAnimationCallbackFrom(
+ backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics),
+ displayMetrics = displayMetrics,
+ onBackProgressed = onBackProgress,
+ onBackStarted = onBackStart,
+ onBackInvoked = onBackInvoke,
+ onBackCancelled = onBackCancel,
+ )
+
+ @Test
+ fun onBackProgressed_shouldInvoke_onBackProgress() {
+ val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT)
+ onBackAnimationCallback.onBackStarted(backEvent)
+
+ onBackAnimationCallback.onBackProgressed(backEvent)
+
+ verify(onBackProgress).invoke(BackTransformation(0f, 0f, 1f))
+ }
+
+ @Test
+ fun onBackStarted_shouldInvoke_onBackStart() {
+ val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT)
+
+ onBackAnimationCallback.onBackStarted(backEvent)
+
+ verify(onBackStart).invoke(backEvent)
+ }
+
+ @Test
+ fun onBackInvoked_shouldInvoke_onBackInvoke() {
+ onBackAnimationCallback.onBackInvoked()
+
+ verify(onBackInvoke).invoke()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
index 34ddf79..8e20303 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -110,6 +110,28 @@
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
+ // MotionEvent.ACTION_HOVER_ENTER
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_ENTER,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
+ expectedInteractionEvent = InteractionEvent.DOWN,
+ expectedPointerOnSensorId = POINTER_ID_1,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_ENTER,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
+ expectedInteractionEvent = InteractionEvent.UNCHANGED,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_ENTER,
+ previousPointerOnSensorId = POINTER_ID_1,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
+ expectedInteractionEvent = InteractionEvent.UP,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
// MotionEvent.ACTION_MOVE
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
@@ -161,6 +183,35 @@
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID_2,
),
+ // MotionEvent.ACTION_HOVER_MOVE
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_MOVE,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
+ expectedInteractionEvent = InteractionEvent.DOWN,
+ expectedPointerOnSensorId = POINTER_ID_1,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_MOVE,
+ previousPointerOnSensorId = POINTER_ID_1,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
+ expectedInteractionEvent = InteractionEvent.UNCHANGED,
+ expectedPointerOnSensorId = POINTER_ID_1,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_MOVE,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
+ expectedInteractionEvent = InteractionEvent.UNCHANGED,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_MOVE,
+ previousPointerOnSensorId = POINTER_ID_1,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
+ expectedInteractionEvent = InteractionEvent.UP,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
// MotionEvent.ACTION_UP
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_UP,
@@ -183,6 +234,28 @@
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
+ // MotionEvent.ACTION_HOVER_EXIT
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_EXIT,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
+ expectedInteractionEvent = InteractionEvent.UP,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_EXIT,
+ previousPointerOnSensorId = POINTER_ID_1,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
+ expectedInteractionEvent = InteractionEvent.UP,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
+ genPositiveTestCases(
+ motionEventAction = MotionEvent.ACTION_HOVER_EXIT,
+ previousPointerOnSensorId = INVALID_POINTER_ID,
+ currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
+ expectedInteractionEvent = InteractionEvent.UNCHANGED,
+ expectedPointerOnSensorId = INVALID_POINTER_ID,
+ ),
// MotionEvent.ACTION_CANCEL
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_CANCEL,
@@ -315,13 +388,7 @@
expectedPointerOnSensorId = POINTER_ID_2
)
)
- .flatten() +
- listOf(
- genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_ENTER),
- genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_MOVE),
- genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT)
- )
- .flatten()
+ .flatten()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
index d159714..d6cafcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
@@ -16,18 +16,23 @@
package com.android.systemui.charging
+import android.graphics.Rect
import android.testing.AndroidTestingRunner
+import android.view.Surface
import android.view.View
import android.view.WindowManager
+import android.view.WindowMetrics
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.surfaceeffects.ripple.RippleView
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.surfaceeffects.ripple.RippleView
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
@@ -35,12 +40,12 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -54,6 +59,7 @@
@Mock private lateinit var rippleView: RippleView
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var windowMetrics: WindowMetrics
private val systemClock = FakeSystemClock()
@Before
@@ -66,6 +72,9 @@
rippleView.setupShader()
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
controller.registerCallbacks()
+
+ `when`(windowMetrics.bounds).thenReturn(Rect(0, 0, 100, 100))
+ `when`(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
}
@Test
@@ -164,4 +173,63 @@
verify(rippleView, never()).addOnAttachStateChangeListener(attachListenerCaptor.capture())
verify(windowManager, never()).addView(eq(rippleView), any<WindowManager.LayoutParams>())
}
+
+ @Test
+ fun testRipple_layoutsCorrectly() {
+ // Sets the correct ripple size.
+ val width = 100
+ val height = 200
+ whenever(windowMetrics.bounds).thenReturn(Rect(0, 0, width, height))
+
+ // Trigger ripple.
+ val captor = ArgumentCaptor
+ .forClass(BatteryController.BatteryStateChangeCallback::class.java)
+ verify(batteryController).addCallback(captor.capture())
+
+ captor.value.onBatteryLevelChanged(
+ /* unusedBatteryLevel= */ 0,
+ /* plugged in= */ true,
+ /* charging= */ false)
+
+ val attachListenerCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+ verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture())
+ verify(windowManager).addView(eq(rippleView), any<WindowManager.LayoutParams>())
+
+ val runnableCaptor =
+ ArgumentCaptor.forClass(Runnable::class.java)
+ attachListenerCaptor.value.onViewAttachedToWindow(rippleView)
+ verify(rippleView).startRipple(runnableCaptor.capture())
+
+ // Verify size and center position.
+ val maxSize = 400f // Double the max value between width and height.
+ verify(rippleView).setMaxSize(maxWidth = maxSize, maxHeight = maxSize)
+
+ val normalizedPortPosX =
+ context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_x)
+ val normalizedPortPosY =
+ context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_y)
+ val expectedCenterX: Float
+ val expectedCenterY: Float
+ when (context.display.rotation) {
+ Surface.ROTATION_90 -> {
+ expectedCenterX = width * normalizedPortPosY
+ expectedCenterY = height * (1 - normalizedPortPosX)
+ }
+ Surface.ROTATION_180 -> {
+ expectedCenterX = width * (1 - normalizedPortPosX)
+ expectedCenterY = height * (1 - normalizedPortPosY)
+ }
+ Surface.ROTATION_270 -> {
+ expectedCenterX = width * (1 - normalizedPortPosY)
+ expectedCenterY = height * normalizedPortPosX
+ }
+ else -> { // Surface.ROTATION_0
+ expectedCenterX = width * normalizedPortPosX
+ expectedCenterY = height * normalizedPortPosY
+ }
+ }
+
+ verify(rippleView).setCenter(expectedCenterX, expectedCenterY)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 25f471b..d54babf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -33,6 +33,7 @@
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserFileManager
@@ -66,6 +67,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.clearInvocations
import org.mockito.MockitoAnnotations
@SmallTest
@@ -88,6 +90,8 @@
private lateinit var userTracker: UserTracker
@Mock
private lateinit var userFileManager: UserFileManager
+ @Mock
+ private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
@Captor
private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo>
@@ -168,6 +172,7 @@
listingController,
userFileManager,
userTracker,
+ authorizedPanelsRepository,
Optional.of(persistenceWrapper),
mock(DumpManager::class.java)
)
@@ -224,6 +229,7 @@
listingController,
userFileManager,
userTracker,
+ authorizedPanelsRepository,
Optional.of(persistenceWrapper),
mock(DumpManager::class.java)
)
@@ -231,6 +237,26 @@
}
@Test
+ fun testAddAuthorizedPackagesFromSavedFavoritesOnStart() {
+ clearInvocations(authorizedPanelsRepository)
+ `when`(persistenceWrapper.readFavorites()).thenReturn(listOf(TEST_STRUCTURE_INFO))
+ ControlsControllerImpl(
+ mContext,
+ delayableExecutor,
+ uiController,
+ bindingController,
+ listingController,
+ userFileManager,
+ userTracker,
+ authorizedPanelsRepository,
+ Optional.of(persistenceWrapper),
+ mock(DumpManager::class.java)
+ )
+ verify(authorizedPanelsRepository)
+ .addAuthorizedPanels(setOf(TEST_STRUCTURE_INFO.componentName.packageName))
+ }
+
+ @Test
fun testOnActionResponse() {
controller.onActionResponse(TEST_COMPONENT, TEST_CONTROL_ID, ControlAction.RESPONSE_OK)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
index 765c4c0..226ef3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
@@ -21,12 +21,15 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.settingslib.core.lifecycle.Lifecycle
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -36,8 +39,10 @@
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.text.Collator
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -49,25 +54,18 @@
@Mock lateinit var lifecycle: Lifecycle
@Mock lateinit var controlsListingController: ControlsListingController
@Mock lateinit var layoutInflater: LayoutInflater
- @Mock lateinit var onAppSelected: (ComponentName?) -> Unit
+ @Mock lateinit var onAppSelected: (ControlsServiceInfo) -> Unit
@Mock lateinit var favoritesRenderer: FavoritesRenderer
val resources: Resources = context.resources
lateinit var adapter: AppAdapter
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- adapter = AppAdapter(backgroundExecutor,
- uiExecutor,
- lifecycle,
- controlsListingController,
- layoutInflater,
- onAppSelected,
- favoritesRenderer,
- resources)
}
@Test
fun testOnServicesUpdated_nullLoadLabel() {
+ adapter = createAdapterWithAuthorizedPanels(emptySet())
val captor = ArgumentCaptor
.forClass(ControlsListingController.ControlsListingCallback::class.java)
val controlsServiceInfo = mock<ControlsServiceInfo>()
@@ -76,14 +74,14 @@
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
captor.value.onServicesUpdated(serviceInfo)
- backgroundExecutor.runAllReady()
- uiExecutor.runAllReady()
+ FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
assertThat(adapter.itemCount).isEqualTo(serviceInfo.size)
}
@Test
- fun testOnServicesUpdatedDoesntHavePanels() {
+ fun testOnServicesUpdated_showsNotAuthorizedPanels() {
+ adapter = createAdapterWithAuthorizedPanels(emptySet())
val captor = ArgumentCaptor
.forClass(ControlsListingController.ControlsListingCallback::class.java)
val serviceInfo = listOf(
@@ -93,20 +91,88 @@
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
captor.value.onServicesUpdated(serviceInfo)
- backgroundExecutor.runAllReady()
- uiExecutor.runAllReady()
+ FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
+
+ assertThat(adapter.itemCount).isEqualTo(2)
+ }
+
+ @Test
+ fun testOnServicesUpdated_doesntShowAuthorizedPanels() {
+ adapter = createAdapterWithAuthorizedPanels(setOf(TEST_PACKAGE))
+
+ val captor = ArgumentCaptor
+ .forClass(ControlsListingController.ControlsListingCallback::class.java)
+ val serviceInfo = listOf(
+ ControlsServiceInfo("no panel", null),
+ ControlsServiceInfo("panel", ComponentName(TEST_PACKAGE, "cls"))
+ )
+ verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
+
+ captor.value.onServicesUpdated(serviceInfo)
+ FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
assertThat(adapter.itemCount).isEqualTo(1)
}
- fun ControlsServiceInfo(
- label: CharSequence,
- panelComponentName: ComponentName? = null
- ): ControlsServiceInfo {
- return mock {
- `when`(this.loadLabel()).thenReturn(label)
- `when`(this.panelActivity).thenReturn(panelComponentName)
- `when`(this.loadIcon()).thenReturn(mock())
+ @Test
+ fun testOnBindSetsClickListenerToCallOnAppSelected() {
+ adapter = createAdapterWithAuthorizedPanels(emptySet())
+
+ val captor = ArgumentCaptor
+ .forClass(ControlsListingController.ControlsListingCallback::class.java)
+ val serviceInfo = listOf(
+ ControlsServiceInfo("no panel", null),
+ ControlsServiceInfo("panel", ComponentName(TEST_PACKAGE, "cls"))
+ )
+ verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
+
+ captor.value.onServicesUpdated(serviceInfo)
+ FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
+
+ val sorted = serviceInfo.sortedWith(
+ compareBy(Collator.getInstance(resources.configuration.locales[0])) {
+ it.loadLabel() ?: ""
+ })
+
+ sorted.forEachIndexed { index, info ->
+ val fakeView: View = mock()
+ val fakeHolder: AppAdapter.Holder = mock()
+ `when`(fakeHolder.view).thenReturn(fakeView)
+
+ clearInvocations(onAppSelected)
+ adapter.onBindViewHolder(fakeHolder, index)
+ val listenerCaptor: ArgumentCaptor<View.OnClickListener> = argumentCaptor()
+ verify(fakeView).setOnClickListener(capture(listenerCaptor))
+ listenerCaptor.value.onClick(fakeView)
+
+ verify(onAppSelected).invoke(info)
}
}
+
+ private fun createAdapterWithAuthorizedPanels(packages: Set<String>): AppAdapter {
+ return AppAdapter(backgroundExecutor,
+ uiExecutor,
+ lifecycle,
+ controlsListingController,
+ layoutInflater,
+ onAppSelected,
+ favoritesRenderer,
+ resources,
+ packages)
+ }
+
+ companion object {
+ private fun ControlsServiceInfo(
+ label: CharSequence,
+ panelComponentName: ComponentName? = null
+ ): ControlsServiceInfo {
+ return mock {
+ `when`(loadLabel()).thenReturn(label)
+ `when`(panelActivity).thenReturn(panelComponentName)
+ `when`(loadIcon()).thenReturn(mock())
+ }
+ }
+
+ private const val TEST_PACKAGE = "package"
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
index 56c3efe..8dfd223 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
@@ -16,7 +16,13 @@
package com.android.systemui.controls.management
+import android.app.Dialog
+import android.content.ComponentName
import android.content.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.ServiceInfo
+import android.graphics.drawable.Drawable
+import android.os.Bundle
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.window.OnBackInvokedCallback
@@ -25,14 +31,23 @@
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
-import com.android.systemui.controls.ui.ControlsUiController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
+import java.util.function.Consumer
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -41,7 +56,11 @@
import org.mockito.ArgumentMatchers
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@SmallTest
@@ -58,9 +77,10 @@
@Mock lateinit var userTracker: UserTracker
- @Mock lateinit var uiController: ControlsUiController
+ @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
- private lateinit var controlsProviderSelectorActivity: ControlsProviderSelectorActivity_Factory
+ @Mock lateinit var dialogFactory: PanelConfirmationDialogFactory
+
private var latch: CountDownLatch = CountDownLatch(1)
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
@@ -81,7 +101,8 @@
listingController,
controlsController,
userTracker,
- uiController,
+ authorizedPanelsRepository,
+ dialogFactory,
mockDispatcher,
latch
)
@@ -113,13 +134,99 @@
verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value)
}
- public class TestableControlsProviderSelectorActivity(
+ @Test
+ fun testOnAppSelectedForNonPanelStartsFavoritingActivity() {
+ val info = ControlsServiceInfo(ComponentName("test_pkg", "service"), "", null)
+ activityRule.activity.onAppSelected(info)
+
+ verifyNoMoreInteractions(dialogFactory)
+
+ assertThat(activityRule.activity.lastStartedActivity?.component?.className)
+ .isEqualTo(ControlsFavoritingActivity::class.java.name)
+
+ assertThat(activityRule.activity.triedToFinish).isTrue()
+ }
+
+ @Test
+ fun testOnAppSelectedForPanelTriggersDialog() {
+ val label = "label"
+ val info =
+ ControlsServiceInfo(
+ ComponentName("test_pkg", "service"),
+ label,
+ ComponentName("test_pkg", "activity")
+ )
+
+ val dialog: Dialog = mock()
+ whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
+
+ activityRule.activity.onAppSelected(info)
+ verify(dialogFactory).createConfirmationDialog(any(), eq(label), any())
+ verify(dialog).show()
+
+ assertThat(activityRule.activity.triedToFinish).isFalse()
+ }
+
+ @Test
+ fun dialogAcceptAddsPackage() {
+ val label = "label"
+ val info =
+ ControlsServiceInfo(
+ ComponentName("test_pkg", "service"),
+ label,
+ ComponentName("test_pkg", "activity")
+ )
+
+ val dialog: Dialog = mock()
+ whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
+
+ activityRule.activity.onAppSelected(info)
+
+ val captor: ArgumentCaptor<Consumer<Boolean>> = argumentCaptor()
+ verify(dialogFactory).createConfirmationDialog(any(), any(), capture(captor))
+
+ captor.value.accept(true)
+
+ val setCaptor: ArgumentCaptor<Set<String>> = argumentCaptor()
+ verify(authorizedPanelsRepository).addAuthorizedPanels(capture(setCaptor))
+ assertThat(setCaptor.value).containsExactly(info.componentName.packageName)
+
+ assertThat(activityRule.activity.triedToFinish).isTrue()
+ }
+
+ @Test
+ fun dialogCancelDoesntAddPackage() {
+ val label = "label"
+ val info =
+ ControlsServiceInfo(
+ ComponentName("test_pkg", "service"),
+ label,
+ ComponentName("test_pkg", "activity")
+ )
+
+ val dialog: Dialog = mock()
+ whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
+
+ activityRule.activity.onAppSelected(info)
+
+ val captor: ArgumentCaptor<Consumer<Boolean>> = argumentCaptor()
+ verify(dialogFactory).createConfirmationDialog(any(), any(), capture(captor))
+
+ captor.value.accept(false)
+
+ verify(authorizedPanelsRepository, never()).addAuthorizedPanels(any())
+
+ assertThat(activityRule.activity.triedToFinish).isFalse()
+ }
+
+ class TestableControlsProviderSelectorActivity(
executor: Executor,
backExecutor: Executor,
listingController: ControlsListingController,
controlsController: ControlsController,
userTracker: UserTracker,
- uiController: ControlsUiController,
+ authorizedPanelsRepository: AuthorizedPanelsRepository,
+ dialogFactory: PanelConfirmationDialogFactory,
private val mockDispatcher: OnBackInvokedDispatcher,
private val latch: CountDownLatch
) :
@@ -129,16 +236,50 @@
listingController,
controlsController,
userTracker,
- uiController
+ authorizedPanelsRepository,
+ dialogFactory
) {
+
+ var lastStartedActivity: Intent? = null
+ var triedToFinish = false
+
override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher {
return mockDispatcher
}
+ override fun startActivity(intent: Intent?, options: Bundle?) {
+ lastStartedActivity = intent
+ }
+
override fun onStop() {
super.onStop()
// ensures that test runner thread does not proceed until ui thread is done
latch.countDown()
}
+
+ override fun animateExitAndFinish() {
+ // Activity should only be finished from the rule.
+ triedToFinish = true
+ }
+ }
+
+ companion object {
+ private fun ControlsServiceInfo(
+ componentName: ComponentName,
+ label: CharSequence,
+ panelComponentName: ComponentName? = null
+ ): ControlsServiceInfo {
+ val serviceInfo =
+ ServiceInfo().apply {
+ applicationInfo = ApplicationInfo()
+ packageName = componentName.packageName
+ name = componentName.className
+ }
+ return Mockito.spy(ControlsServiceInfo(mock(), serviceInfo)).apply {
+ doReturn(label).`when`(this).loadLabel()
+ doReturn(mock<Drawable>()).`when`(this).loadIcon()
+ doReturn(panelComponentName).`when`(this).panelActivity
+ }
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt
new file mode 100644
index 0000000..756f267
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.management
+
+import android.content.DialogInterface
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class PanelConfirmationDialogFactoryTest : SysuiTestCase() {
+
+ @Test
+ fun testDialogHasCorrectInfo() {
+ val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
+ val factory = PanelConfirmationDialogFactory { mockDialog }
+ val appName = "appName"
+
+ factory.createConfirmationDialog(context, appName) {}
+
+ verify(mockDialog).setCanceledOnTouchOutside(true)
+ verify(mockDialog)
+ .setTitle(context.getString(R.string.controls_panel_authorization_title, appName))
+ verify(mockDialog)
+ .setMessage(context.getString(R.string.controls_panel_authorization, appName))
+ }
+
+ @Test
+ fun testDialogPositiveButton() {
+ val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
+ val factory = PanelConfirmationDialogFactory { mockDialog }
+
+ var response: Boolean? = null
+
+ factory.createConfirmationDialog(context, "") { response = it }
+
+ val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor()
+ verify(mockDialog).setPositiveButton(eq(R.string.controls_dialog_ok), capture(captor))
+
+ captor.value.onClick(mockDialog, DialogInterface.BUTTON_POSITIVE)
+
+ assertThat(response).isTrue()
+ }
+
+ @Test
+ fun testDialogNeutralButton() {
+ val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
+ val factory = PanelConfirmationDialogFactory { mockDialog }
+
+ var response: Boolean? = null
+
+ factory.createConfirmationDialog(context, "") { response = it }
+
+ val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor()
+ verify(mockDialog).setNeutralButton(eq(R.string.cancel), capture(captor))
+
+ captor.value.onClick(mockDialog, DialogInterface.BUTTON_NEUTRAL)
+
+ assertThat(response).isFalse()
+ }
+
+ @Test
+ fun testDialogCancel() {
+ val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
+ val factory = PanelConfirmationDialogFactory { mockDialog }
+
+ var response: Boolean? = null
+
+ factory.createConfirmationDialog(context, "") { response = it }
+
+ val captor: ArgumentCaptor<DialogInterface.OnCancelListener> = argumentCaptor()
+ verify(mockDialog).setOnCancelListener(capture(captor))
+
+ captor.value.onCancel(mockDialog)
+
+ assertThat(response).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
new file mode 100644
index 0000000..b91a3fd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
+
+ @Mock private lateinit var userTracker: UserTracker
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf<String>()
+ )
+ whenever(userTracker.userId).thenReturn(0)
+ }
+
+ @Test
+ fun testPreApprovedPackagesAreSeededIfNoSavedPreferences() {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf(TEST_PACKAGE)
+ )
+ val sharedPrefs = FakeSharedPreferences()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+ val repository = createRepository(fileManager)
+
+ assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
+ assertThat(sharedPrefs.getStringSet(KEY, null)).containsExactly(TEST_PACKAGE)
+ }
+
+ @Test
+ fun testPreApprovedPackagesNotSeededIfEmptySavedPreferences() {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf(TEST_PACKAGE)
+ )
+ val sharedPrefs = FakeSharedPreferences()
+ sharedPrefs.edit().putStringSet(KEY, emptySet()).apply()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+ createRepository(fileManager)
+
+ assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty()
+ }
+
+ @Test
+ fun testPreApprovedPackagesOnlySetForUserThatDoesntHaveThem() {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf(TEST_PACKAGE)
+ )
+ val sharedPrefs_0 = FakeSharedPreferences()
+ val sharedPrefs_1 = FakeSharedPreferences()
+ sharedPrefs_1.edit().putStringSet(KEY, emptySet()).apply()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs_0, 1 to sharedPrefs_1))
+ val repository = createRepository(fileManager)
+
+ assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
+ whenever(userTracker.userId).thenReturn(1)
+ assertThat(repository.getAuthorizedPanels()).isEmpty()
+ }
+
+ @Test
+ fun testGetAuthorizedPackages() {
+ val sharedPrefs = FakeSharedPreferences()
+ sharedPrefs.edit().putStringSet(KEY, mutableSetOf(TEST_PACKAGE)).apply()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+
+ val repository = createRepository(fileManager)
+ assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
+ }
+
+ @Test
+ fun testSetAuthorizedPackage() {
+ val sharedPrefs = FakeSharedPreferences()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+
+ val repository = createRepository(fileManager)
+ repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
+ assertThat(sharedPrefs.getStringSet(KEY, null)).containsExactly(TEST_PACKAGE)
+ }
+
+ private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl {
+ return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker)
+ }
+
+ private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) :
+ UserFileManager {
+ override fun getFile(fileName: String, userId: Int): File {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getSharedPreferences(
+ fileName: String,
+ mode: Int,
+ userId: Int
+ ): SharedPreferences {
+ if (fileName != FILE_NAME) {
+ throw IllegalArgumentException("Preference files must be $FILE_NAME")
+ }
+ return sharedPrefs.getValue(userId)
+ }
+ }
+
+ companion object {
+ private const val FILE_NAME = "controls_prefs"
+ private const val KEY = "authorized_panels"
+ private const val TEST_PACKAGE = "package"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index edc6882..ed40c90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -39,8 +39,10 @@
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
@@ -91,6 +93,8 @@
@Mock lateinit var userTracker: UserTracker
@Mock lateinit var taskViewFactory: TaskViewFactory
@Mock lateinit var dumpManager: DumpManager
+ @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
+ @Mock lateinit var featureFlags: FeatureFlags
val sharedPreferences = FakeSharedPreferences()
lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
@@ -132,6 +136,8 @@
userTracker,
Optional.of(taskViewFactory),
controlsSettingsRepository,
+ authorizedPanelsRepository,
+ featureFlags,
dumpManager
)
`when`(
@@ -240,7 +246,9 @@
@Test
fun testPanelCallsTaskViewFactoryCreate() {
mockLayoutInflater()
- val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
+ val packageName = "pkg"
+ `when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
+ val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
val serviceInfo = setUpPanel(panel)
underTest.show(parent, {}, context)
@@ -258,9 +266,11 @@
@Test
fun testPanelControllerStartActivityWithCorrectArguments() {
mockLayoutInflater()
+ val packageName = "pkg"
+ `when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
- val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
+ val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
val serviceInfo = setUpPanel(panel)
underTest.show(parent, {}, context)
@@ -290,9 +300,11 @@
@Test
fun testPendingIntentExtrasAreModified() {
mockLayoutInflater()
+ val packageName = "pkg"
+ `when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
- val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
+ val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
val serviceInfo = setUpPanel(panel)
underTest.show(parent, {}, context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
new file mode 100644
index 0000000..19347c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.conditions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.condition.Condition;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamConditionTest extends SysuiTestCase {
+ @Mock
+ Context mContext;
+
+ @Mock
+ Condition.Callback mCallback;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Ensure a dreaming state immediately triggers the condition.
+ */
+ @Test
+ public void testInitialState() {
+ final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+ when(mContext.registerReceiver(any(), any())).thenReturn(intent);
+ final DreamCondition condition = new DreamCondition(mContext);
+ condition.addCallback(mCallback);
+ condition.start();
+
+ verify(mCallback).onConditionChanged(eq(condition));
+ assertThat(condition.isConditionMet()).isTrue();
+ }
+
+ /**
+ * Ensure that changing dream state triggers condition.
+ */
+ @Test
+ public void testChange() {
+ final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ when(mContext.registerReceiver(receiverCaptor.capture(), any())).thenReturn(intent);
+ final DreamCondition condition = new DreamCondition(mContext);
+ condition.addCallback(mCallback);
+ condition.start();
+ clearInvocations(mCallback);
+ receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+ verify(mCallback).onConditionChanged(eq(condition));
+ assertThat(condition.isConditionMet()).isFalse();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 0a03b2c..c0af0cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -173,6 +173,7 @@
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
set(Flags.REVAMPED_WALLPAPER_UI, true)
+ set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
},
repository = { quickAffordanceRepository },
launchAnimator = launchAnimator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 5a7a3d4..3a871b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -519,6 +519,43 @@
}
@Test
+ fun `GONE to LOCKSREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to GONE
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the keyguard starts to show
+ keyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.GONE)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
fun `GONE to DREAMING`() =
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
index c88f84a..54fc493 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
@@ -71,7 +71,7 @@
waitUntilComplete(info.animator!!)
}
- suspend private fun waitUntilComplete(animator: ValueAnimator) {
+ private suspend fun waitUntilComplete(animator: ValueAnimator) {
withContext(Dispatchers.Main) {
val startTime = System.currentTimeMillis()
while (!isTerminated && animator.isRunning()) {
@@ -96,6 +96,6 @@
override fun setFrameDelay(delay: Long) {}
companion object {
- private const val MAX_TEST_DURATION = 100L
+ private const val MAX_TEST_DURATION = 200L
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 1687fdc..1ac6695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -134,7 +134,8 @@
private val clock = FakeSystemClock()
@Mock private lateinit var tunerService: TunerService
@Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable>
- @Captor lateinit var callbackCaptor: ArgumentCaptor<(String, PlaybackState) -> Unit>
+ @Captor lateinit var stateCallbackCaptor: ArgumentCaptor<(String, PlaybackState) -> Unit>
+ @Captor lateinit var sessionCallbackCaptor: ArgumentCaptor<(String) -> Unit>
@Captor lateinit var smartSpaceConfigBuilderCaptor: ArgumentCaptor<SmartspaceConfig>
private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)
@@ -184,6 +185,8 @@
)
verify(tunerService)
.addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
+ verify(mediaTimeoutListener).stateCallback = capture(stateCallbackCaptor)
+ verify(mediaTimeoutListener).sessionCallback = capture(sessionCallbackCaptor)
session = MediaSession(context, "MediaDataManagerTestSession")
mediaNotification =
SbnBuilder().run {
@@ -230,6 +233,7 @@
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
whenever(mediaFlags.isExplicitIndicatorEnabled()).thenReturn(true)
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
}
@@ -547,6 +551,7 @@
mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
+
verify(listener)
.onMediaDataLoaded(
eq(KEY),
@@ -558,9 +563,21 @@
)
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
- val resumableData = data.copy(resumeAction = Runnable {})
- mediaDataManager.onMediaDataLoaded(KEY, null, resumableData)
- mediaDataManager.onMediaDataLoaded(KEY_2, null, resumableData)
+
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY_2),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ val data2 = mediaDataCaptor.value
+ assertThat(data2.resumption).isFalse()
+
+ mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+ mediaDataManager.onMediaDataLoaded(KEY_2, null, data2.copy(resumeAction = Runnable {}))
reset(listener)
// WHEN the first is removed
mediaDataManager.onNotificationRemoved(KEY)
@@ -1310,11 +1327,10 @@
fun testPlaybackStateChange_keyExists_callsListener() {
// Notification has been added
addNotificationAndLoad()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
// Callback gets an updated state
val state = PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build()
- callbackCaptor.value.invoke(KEY, state)
+ stateCallbackCaptor.value.invoke(KEY, state)
// Listener is notified of updated state
verify(listener)
@@ -1332,11 +1348,10 @@
@Test
fun testPlaybackStateChange_keyDoesNotExist_doesNothing() {
val state = PlaybackState.Builder().build()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
// No media added with this key
- callbackCaptor.value.invoke(KEY, state)
+ stateCallbackCaptor.value.invoke(KEY, state)
verify(listener, never())
.onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(), anyBoolean())
}
@@ -1352,10 +1367,9 @@
// And then get a state update
val state = PlaybackState.Builder().build()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
// Then no changes are made
- callbackCaptor.value.invoke(KEY, state)
+ stateCallbackCaptor.value.invoke(KEY, state)
verify(listener, never())
.onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(), anyBoolean())
}
@@ -1367,8 +1381,7 @@
whenever(controller.playbackState).thenReturn(state)
addNotificationAndLoad()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
- callbackCaptor.value.invoke(KEY, state)
+ stateCallbackCaptor.value.invoke(KEY, state)
verify(listener)
.onMediaDataLoaded(
@@ -1410,8 +1423,7 @@
backgroundExecutor.runAllReady()
foregroundExecutor.runAllReady()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
- callbackCaptor.value.invoke(PACKAGE_NAME, state)
+ stateCallbackCaptor.value.invoke(PACKAGE_NAME, state)
verify(listener)
.onMediaDataLoaded(
@@ -1436,8 +1448,7 @@
.build()
addNotificationAndLoad()
- verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
- callbackCaptor.value.invoke(KEY, state)
+ stateCallbackCaptor.value.invoke(KEY, state)
verify(listener)
.onMediaDataLoaded(
@@ -1485,6 +1496,177 @@
assertThat(mediaDataCaptor.value.isClearable).isFalse()
}
+ @Test
+ fun testRetain_notifPlayer_notifRemoved_setToResume() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+
+ // When a media control based on notification is added, times out, and then removed
+ addNotificationAndLoad()
+ mediaDataManager.setTimedOut(KEY, timedOut = true)
+ assertThat(mediaDataCaptor.value.active).isFalse()
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // It is converted to a resume player
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.resumption).isTrue()
+ assertThat(mediaDataCaptor.value.active).isFalse()
+ verify(logger)
+ .logActiveConvertedToResume(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId)
+ )
+ }
+
+ @Test
+ fun testRetain_notifPlayer_sessionDestroyed_doesNotChange() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+
+ // When a media control based on notification is added and times out
+ addNotificationAndLoad()
+ mediaDataManager.setTimedOut(KEY, timedOut = true)
+ assertThat(mediaDataCaptor.value.active).isFalse()
+
+ // and then the session is destroyed
+ sessionCallbackCaptor.value.invoke(KEY)
+
+ // It remains as a regular player
+ verify(listener, never()).onMediaDataRemoved(eq(KEY))
+ verify(listener, never())
+ .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testRetain_notifPlayer_removeWhileActive_fullyRemoved() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+
+ // When a media control based on notification is added and then removed, without timing out
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.active).isTrue()
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // It is fully removed
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+ verify(listener, never())
+ .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testRetain_canResume_removeWhileActive_setToResume() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+
+ // When a media control that supports resumption is added
+ addNotificationAndLoad()
+ val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
+ mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+
+ // And then removed while still active
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // It is converted to a resume player
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.resumption).isTrue()
+ assertThat(mediaDataCaptor.value.active).isFalse()
+ verify(logger)
+ .logActiveConvertedToResume(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId)
+ )
+ }
+
+ @Test
+ fun testRetain_sessionPlayer_notifRemoved_doesNotChange() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+ addPlaybackStateAction()
+
+ // When a media control with PlaybackState actions is added, times out,
+ // and then the notification is removed
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.active).isTrue()
+ mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // It remains as a regular player
+ verify(listener, never()).onMediaDataRemoved(eq(KEY))
+ verify(listener, never())
+ .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testRetain_sessionPlayer_sessionDestroyed_setToResume() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+ addPlaybackStateAction()
+
+ // When a media control with PlaybackState actions is added, times out,
+ // and then the session is destroyed
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.active).isTrue()
+ mediaDataManager.setTimedOut(KEY, timedOut = true)
+ sessionCallbackCaptor.value.invoke(KEY)
+
+ // It is converted to a resume player
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.resumption).isTrue()
+ assertThat(mediaDataCaptor.value.active).isFalse()
+ verify(logger)
+ .logActiveConvertedToResume(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId)
+ )
+ }
+
+ @Test
+ fun testRetain_sessionPlayer_destroyedWhileActive_fullyRemoved() {
+ whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+ addPlaybackStateAction()
+
+ // When a media control using session actions is added, and then the session is destroyed
+ // without timing out first
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.active).isTrue()
+ sessionCallbackCaptor.value.invoke(KEY)
+
+ // It is fully removed
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+ verify(listener, never())
+ .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ }
+
/** Helper function to add a media notification and capture the resulting MediaData */
private fun addNotificationAndLoad() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
@@ -1500,4 +1682,12 @@
eq(false)
)
}
+
+ /** Helper function to set up a PlaybackState with action */
+ private fun addPlaybackStateAction() {
+ val stateActions = PlaybackState.ACTION_PLAY_PAUSE
+ val stateBuilder = PlaybackState.Builder().setActions(stateActions)
+ stateBuilder.setState(PlaybackState.STATE_PAUSED, 0, 1.0f)
+ whenever(controller.playbackState).thenReturn(stateBuilder.build())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
index 344dffa..92bf84c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
@@ -72,6 +72,7 @@
private lateinit var executor: FakeExecutor
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
@Mock private lateinit var stateCallback: (String, PlaybackState) -> Unit
+ @Mock private lateinit var sessionCallback: (String) -> Unit
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
@Captor
private lateinit var dozingCallbackCaptor:
@@ -99,6 +100,7 @@
)
mediaTimeoutListener.timeoutCallback = timeoutCallback
mediaTimeoutListener.stateCallback = stateCallback
+ mediaTimeoutListener.sessionCallback = sessionCallback
// Create a media session and notification for testing.
metadataBuilder =
@@ -284,6 +286,7 @@
verify(mediaController).unregisterCallback(anyObject())
assertThat(executor.numPending()).isEqualTo(0)
verify(logger).logSessionDestroyed(eq(KEY))
+ verify(sessionCallback).invoke(eq(KEY))
}
@Test
@@ -322,6 +325,7 @@
// THEN the controller is unregistered, but the timeout is still scheduled
verify(mediaController).unregisterCallback(anyObject())
assertThat(executor.numPending()).isEqualTo(1)
+ verify(sessionCallback, never()).invoke(eq(KEY))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 094d69a..9a0bd9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -243,6 +243,13 @@
}
@Test
+ public void dismissDialog_closesDialogByBroadcastSender() {
+ mMediaOutputBaseDialogImpl.dismissDialog();
+
+ verify(mBroadcastSender).closeSystemDialogs();
+ }
+
+ @Test
public void whenBroadcasting_verifyLeBroadcastServiceCallBackIsRegisteredAndUnregistered() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index f5432e2..117751c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -252,6 +252,13 @@
}
@Test
+ public void tryToLaunchMediaApplication_nullIntent_skip() {
+ mMediaOutputController.tryToLaunchMediaApplication();
+
+ verify(mCb, never()).dismissDialog();
+ }
+
+ @Test
public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
mMediaOutputController.start(mCb);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
index 9c4e849..b3e621e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
@@ -48,6 +48,7 @@
viewUtil: ViewUtil,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
+ rippleController: MediaTttReceiverRippleController,
) :
MediaTttChipControllerReceiver(
commandQueue,
@@ -65,6 +66,7 @@
viewUtil,
wakeLockBuilder,
systemClock,
+ rippleController,
) {
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
// Just bypass the animation in tests
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index cefc742..5e40898 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -85,6 +85,8 @@
private lateinit var windowManager: WindowManager
@Mock
private lateinit var commandQueue: CommandQueue
+ @Mock
+ private lateinit var rippleController: MediaTttReceiverRippleController
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
private lateinit var uiEventLoggerFake: UiEventLoggerFake
@@ -134,6 +136,7 @@
viewUtil,
fakeWakeLockBuilder,
fakeClock,
+ rippleController,
)
controllerReceiver.start()
@@ -163,6 +166,7 @@
viewUtil,
fakeWakeLockBuilder,
fakeClock,
+ rippleController,
)
controllerReceiver.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
index b6a595b..7ba2cf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -35,9 +35,33 @@
@Test
fun testCreateShareIntent() {
val uri = Uri.parse("content://fake")
+
+ val output = ActionIntentCreator.createShareIntent(uri)
+
+ assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
+ assertFlagsSet(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ output.flags
+ )
+
+ val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+ assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
+ assertThat(wrappedIntent?.data).isEqualTo(uri)
+ assertThat(wrappedIntent?.type).isEqualTo("image/png")
+ assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
+ assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
+ assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
+ .isEqualTo(uri)
+ }
+
+ @Test
+ fun testCreateShareIntentWithSubject() {
+ val uri = Uri.parse("content://fake")
val subject = "Example subject"
- val output = ActionIntentCreator.createShareIntent(uri, subject)
+ val output = ActionIntentCreator.createShareIntentWithSubject(uri, subject)
assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
assertFlagsSet(
@@ -52,16 +76,34 @@
assertThat(wrappedIntent?.data).isEqualTo(uri)
assertThat(wrappedIntent?.type).isEqualTo("image/png")
assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isEqualTo(subject)
+ assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
.isEqualTo(uri)
}
@Test
- fun testCreateShareIntent_noSubject() {
+ fun testCreateShareIntentWithExtraText() {
val uri = Uri.parse("content://fake")
- val output = ActionIntentCreator.createShareIntent(uri, null)
+ val extraText = "Extra text"
+
+ val output = ActionIntentCreator.createShareIntentWithExtraText(uri, extraText)
+
+ assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
+ assertFlagsSet(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ output.flags
+ )
+
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+ assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
+ assertThat(wrappedIntent?.data).isEqualTo(uri)
+ assertThat(wrappedIntent?.type).isEqualTo("image/png")
assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
+ assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(extraText)
+ assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
+ .isEqualTo(uri)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index ed3f1a0..541d6c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -73,6 +73,30 @@
assertThat(result).isEqualTo(request)
}
+ /** Tests the Java-compatible function wrapper, ensures callback is invoked. */
+ @Test
+ fun testProcessAsync_ScreenshotData() {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
+ val request = ScreenshotData.fromRequest(
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build())
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ var result: ScreenshotData? = null
+ var callbackCount = 0
+ val callback: (ScreenshotData) -> Unit = { processedRequest: ScreenshotData ->
+ result = processedRequest
+ callbackCount++
+ }
+
+ // runs synchronously, using Unconfined Dispatcher
+ processor.processAsync(request, callback)
+
+ // Callback invoked once returning the same request (no changes)
+ assertThat(callbackCount).isEqualTo(1)
+ assertThat(result).isEqualTo(request)
+ }
+
@Test
fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking {
flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
@@ -85,6 +109,11 @@
// No changes
assertThat(processedRequest).isEqualTo(request)
+
+ val screenshotData = ScreenshotData.fromRequest(request)
+ val processedData = processor.process(screenshotData)
+
+ assertThat(processedData).isEqualTo(screenshotData)
}
@Test
@@ -108,6 +137,13 @@
assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
assertThat(processedRequest.source).isEqualTo(SCREENSHOT_OTHER)
assertThat(processedRequest.topComponent).isEqualTo(component)
+
+ val processedData = processor.process(ScreenshotData.fromRequest(request))
+
+ // Request has topComponent added, but otherwise unchanged.
+ assertThat(processedData.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
+ assertThat(processedData.source).isEqualTo(SCREENSHOT_OTHER)
+ assertThat(processedData.topComponent).isEqualTo(component)
}
@Test
@@ -140,6 +176,18 @@
assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
assertThat(processedRequest.userId).isEqualTo(USER_ID)
assertThat(processedRequest.topComponent).isEqualTo(component)
+
+ val processedData = processor.process(ScreenshotData.fromRequest(request))
+
+ // Expect a task snapshot is taken, overriding the full screen mode
+ assertThat(processedData.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
+ assertThat(processedData.bitmap).isEqualTo(bitmap)
+ assertThat(processedData.screenBounds).isEqualTo(bounds)
+ assertThat(processedData.insets).isEqualTo(Insets.NONE)
+ assertThat(processedData.taskId).isEqualTo(TASK_ID)
+ assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
+ assertThat(processedRequest.userId).isEqualTo(USER_ID)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
}
@Test
@@ -165,6 +213,11 @@
// No changes
assertThat(processedRequest).isEqualTo(request)
+
+ val screenshotData = ScreenshotData.fromRequest(request)
+ val processedData = processor.process(screenshotData)
+
+ assertThat(processedData).isEqualTo(screenshotData)
}
@Test
@@ -192,6 +245,11 @@
// No changes
assertThat(processedRequest).isEqualTo(request)
+
+ val screenshotData = ScreenshotData.fromRequest(request)
+ val processedData = processor.process(screenshotData)
+
+ assertThat(processedData).isEqualTo(screenshotData)
}
@Test
@@ -220,6 +278,11 @@
// Work profile, but already a task snapshot, so no changes
assertThat(processedRequest).isEqualTo(request)
+
+ val screenshotData = ScreenshotData.fromRequest(request)
+ val processedData = processor.process(screenshotData)
+
+ assertThat(processedData).isEqualTo(screenshotData)
}
private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
new file mode 100644
index 0000000..43e9939
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.ComponentName
+import android.graphics.Insets
+import android.graphics.Rect
+import android.os.UserHandle
+import android.view.WindowManager
+import com.android.internal.util.ScreenshotRequest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ScreenshotDataTest {
+ private val type = WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+ private val source = WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
+ private val bounds = Rect(1, 2, 3, 4)
+ private val taskId = 123
+ private val userId = 1
+ private val insets = Insets.of(1, 2, 3, 4)
+ private val component = ComponentName("android.test", "android.test.Component")
+
+ @Test
+ fun testConstruction() {
+ val request =
+ ScreenshotRequest.Builder(type, source)
+ .setBoundsOnScreen(bounds)
+ .setInsets(insets)
+ .setTaskId(taskId)
+ .setUserId(userId)
+ .setTopComponent(component)
+ .build()
+
+ val data = ScreenshotData.fromRequest(request)
+
+ assertThat(data.source).isEqualTo(source)
+ assertThat(data.type).isEqualTo(type)
+ assertThat(data.screenBounds).isEqualTo(bounds)
+ assertThat(data.insets).isEqualTo(insets)
+ assertThat(data.taskId).isEqualTo(taskId)
+ assertThat(data.userHandle).isEqualTo(UserHandle.of(userId))
+ assertThat(data.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testNegativeUserId() {
+ val request = ScreenshotRequest.Builder(type, source).setUserId(-1).build()
+
+ val data = ScreenshotData.fromRequest(request)
+
+ assertThat(data.userHandle).isNull()
+ }
+
+ @Test
+ fun testPackageNameAsString() {
+ val request = ScreenshotRequest.Builder(type, source).setTopComponent(component).build()
+
+ val data = ScreenshotData.fromRequest(request)
+
+ assertThat(data.packageNameString).isEqualTo("android.test")
+ }
+
+ @Test
+ fun testPackageNameAsString_null() {
+ val request = ScreenshotRequest.Builder(type, source).build()
+
+ val data = ScreenshotData.fromRequest(request)
+
+ assertThat(data.packageNameString).isEqualTo("")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index f935019..74969d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -29,7 +29,7 @@
import android.os.UserHandle
import android.os.UserManager
import android.testing.AndroidTestingRunner
-import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
+import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
@@ -39,7 +39,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
-import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_CHORD
+import com.android.systemui.flags.Flags.SCREENSHOT_METADATA
+import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
import com.android.systemui.util.mockito.any
@@ -106,15 +107,22 @@
// Stub request processor as a synchronous no-op for tests with the flag enabled
doAnswer {
- val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
- val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
- consumer.accept(request)
- }
- .`when`(requestProcessor)
- .processAsync(/* request= */ any(), /* callback= */ any())
+ val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
+ val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
+ consumer.accept(request)
+ }.`when`(requestProcessor).processAsync(
+ /* request= */ any(ScreenshotRequest::class.java), /* callback= */ any())
+
+ doAnswer {
+ val request: ScreenshotData = it.getArgument(0) as ScreenshotData
+ val consumer: Consumer<ScreenshotData> = it.getArgument(1)
+ consumer.accept(request)
+ }.`when`(requestProcessor).processAsync(
+ /* screenshot= */ any(ScreenshotData::class.java), /* callback= */ any())
// Flipped in selected test cases
flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false)
+ flags.set(SCREENSHOT_METADATA, false)
service.attach(
mContext,
@@ -141,7 +149,7 @@
@Test
fun takeScreenshotFullscreen() {
val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER)
.setTopComponent(topComponent)
.build()
@@ -157,16 +165,34 @@
assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
val logEvent = eventLogger.get(0)
- assertEquals(
- "Expected SCREENSHOT_REQUESTED UiEvent",
- logEvent.eventId,
- SCREENSHOT_REQUESTED_KEY_CHORD.id
- )
- assertEquals(
- "Expected supplied package name",
- topComponent.packageName,
- eventLogger.get(0).packageName
- )
+ assertEquals("Expected SCREENSHOT_REQUESTED UiEvent",
+ logEvent.eventId, SCREENSHOT_REQUESTED_KEY_OTHER.id)
+ assertEquals("Expected supplied package name",
+ topComponent.packageName, eventLogger.get(0).packageName)
+ }
+
+ @Test
+ fun takeScreenshotFullscreen_screenshotDataEnabled() {
+ flags.set(SCREENSHOT_METADATA, true)
+
+ val request = ScreenshotRequest.Builder(
+ TAKE_SCREENSHOT_FULLSCREEN,
+ SCREENSHOT_KEY_OTHER).setTopComponent(topComponent).build()
+
+ service.handleRequest(request, { /* onSaved */ }, callback)
+
+ verify(controller, times(1)).handleScreenshot(
+ eq(ScreenshotData.fromRequest(request)),
+ /* onSavedListener = */ any(),
+ /* requestCallback = */ any())
+
+ assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
+ val logEvent = eventLogger.get(0)
+
+ assertEquals("Expected SCREENSHOT_REQUESTED UiEvent",
+ logEvent.eventId, SCREENSHOT_REQUESTED_KEY_OTHER.id)
+ assertEquals("Expected supplied package name",
+ topComponent.packageName, eventLogger.get(0).packageName)
}
@Test
@@ -218,7 +244,7 @@
whenever(userManager.isUserUnlocked).thenReturn(false)
val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER)
.setTopComponent(topComponent)
.build()
@@ -244,7 +270,7 @@
.thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN")
val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER)
.setTopComponent(topComponent)
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
index 5a62cc1..ae1c8cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
@@ -1,21 +1,17 @@
package com.android.systemui.shared.regionsampling
-import android.graphics.Rect
+import android.app.WallpaperManager
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper
import java.io.PrintWriter
import java.util.concurrent.Executor
-import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.clearInvocations
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@@ -28,9 +24,8 @@
@Mock private lateinit var sampledView: View
@Mock private lateinit var mainExecutor: Executor
@Mock private lateinit var bgExecutor: Executor
- @Mock private lateinit var regionSampler: RegionSamplingHelper
@Mock private lateinit var pw: PrintWriter
- @Mock private lateinit var callback: RegionSamplingHelper.SamplingCallback
+ @Mock private lateinit var wallpaperManager: WallpaperManager
private lateinit var mRegionSampler: RegionSampler
private var updateFun: UpdateColorCallback = {}
@@ -38,65 +33,18 @@
@Before
fun setUp() {
whenever(sampledView.isAttachedToWindow).thenReturn(true)
- whenever(regionSampler.callback).thenReturn(this@RegionSamplerTest.callback)
mRegionSampler =
- object : RegionSampler(sampledView, mainExecutor, bgExecutor, true, updateFun) {
- override fun createRegionSamplingHelper(
- sampledView: View,
- callback: RegionSamplingHelper.SamplingCallback,
- mainExecutor: Executor?,
- bgExecutor: Executor?
- ): RegionSamplingHelper {
- return this@RegionSamplerTest.regionSampler
- }
- }
+ RegionSampler(sampledView, mainExecutor, bgExecutor, true, updateFun, wallpaperManager)
}
@Test
fun testStartRegionSampler() {
mRegionSampler.startRegionSampler()
-
- verify(regionSampler).start(Rect(0, 0, 0, 0))
- }
-
- @Test
- fun testStopRegionSampler() {
- mRegionSampler.stopRegionSampler()
-
- verify(regionSampler).stop()
}
@Test
fun testDump() {
mRegionSampler.dump(pw)
-
- verify(regionSampler).dump(pw)
- }
-
- @Test
- fun testUpdateColorCallback() {
- regionSampler.callback.onRegionDarknessChanged(false)
- verify(regionSampler.callback).onRegionDarknessChanged(false)
- clearInvocations(regionSampler.callback)
- regionSampler.callback.onRegionDarknessChanged(true)
- verify(regionSampler.callback).onRegionDarknessChanged(true)
- }
-
- @Test
- fun testFlagFalse() {
- mRegionSampler =
- object : RegionSampler(sampledView, mainExecutor, bgExecutor, false, updateFun) {
- override fun createRegionSamplingHelper(
- sampledView: View,
- callback: RegionSamplingHelper.SamplingCallback,
- mainExecutor: Executor?,
- bgExecutor: Executor?
- ): RegionSamplingHelper {
- return this@RegionSamplerTest.regionSampler
- }
- }
-
- Assert.assertEquals(mRegionSampler.regionSampler, null)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
index d29e9a6..fa7d869 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
@@ -20,8 +20,6 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.util.concurrency.Execution
@@ -41,9 +39,6 @@
@TestableLooper.RunWithLooper
class LockscreenPreconditionTest : SysuiTestCase() {
@Mock
- private lateinit var featureFlags: FeatureFlags
-
- @Mock
private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock
@@ -64,10 +59,7 @@
fun testFullyEnabled() {
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
- `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
- .thenReturn(true)
- val precondition = LockscreenPrecondition(featureFlags, deviceProvisionedController,
- execution)
+ val precondition = LockscreenPrecondition(deviceProvisionedController, execution)
precondition.addListener(listener)
`verify`(listener).onCriteriaChanged()
@@ -81,10 +73,8 @@
fun testProvisioning() {
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
- `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
- .thenReturn(true)
val precondition =
- LockscreenPrecondition(featureFlags, deviceProvisionedController, execution)
+ LockscreenPrecondition(deviceProvisionedController, execution)
precondition.addListener(listener)
verify(listener).onCriteriaChanged()
@@ -109,10 +99,8 @@
fun testUserSetup() {
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
- `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
- .thenReturn(true)
val precondition =
- LockscreenPrecondition(featureFlags, deviceProvisionedController, execution)
+ LockscreenPrecondition(deviceProvisionedController, execution)
precondition.addListener(listener)
verify(listener).onCriteriaChanged()
@@ -129,4 +117,4 @@
verify(listener).onCriteriaChanged()
assertThat(precondition.conditionsMet()).isTrue()
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index fc7cd89..0000c32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -209,9 +209,9 @@
@Test
public void testShowRecentApps() {
- mCommandQueue.showRecentApps(true, false);
+ mCommandQueue.showRecentApps(true);
waitForIdleSync();
- verify(mCallbacks).showRecentApps(eq(true), eq(false));
+ verify(mCallbacks).showRecentApps(eq(true));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 5124eb9..e6f272b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -37,6 +37,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -152,4 +153,18 @@
// and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ.
assertEquals(0.99f, controller.dozeAmount, 0.009f)
}
+
+ @Test
+ fun testSetDreamState_invokesCallback() {
+ val listener = mock(StatusBarStateController.StateListener::class.java)
+ controller.addCallback(listener)
+
+ controller.setIsDreaming(true)
+ verify(listener).onDreamingChanged(true)
+
+ Mockito.clearInvocations(listener)
+
+ controller.setIsDreaming(false)
+ verify(listener).onDreamingChanged(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 4bcb54d..43b6e41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -34,7 +34,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
@@ -177,8 +176,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(featureFlags.isEnabled(Flags.SMARTSPACE)).thenReturn(true)
-
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
.thenReturn(fakePrivateLockscreenSettingUri)
`when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
@@ -221,17 +218,6 @@
deviceProvisionedListener = deviceProvisionedCaptor.value
}
- @Test(expected = RuntimeException::class)
- fun testThrowsIfFlagIsDisabled() {
- // GIVEN the feature flag is disabled
- `when`(featureFlags.isEnabled(Flags.SMARTSPACE)).thenReturn(false)
-
- // WHEN we try to build the view
- controller.buildAndConnectView(fakeParent)
-
- // THEN an exception is thrown
- }
-
@Test
fun connectOnlyAfterDeviceIsProvisioned() {
// GIVEN an unprovisioned device and an attempt to connect
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index be6b1dc..2686238 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -321,7 +321,7 @@
val testDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
val fakeSettings = FakeSettings().apply {
- putBool(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, true)
+ putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
}
val seenNotificationsProvider = SeenNotificationsProviderImpl()
val keyguardCoordinator =
@@ -372,14 +372,14 @@
var showOnlyUnseenNotifsOnKeyguardSetting: Boolean
get() =
- fakeSettings.getBoolForUser(
+ fakeSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
UserHandle.USER_CURRENT,
- )
+ ) == 1
set(value) {
- fakeSettings.putBoolForUser(
+ fakeSettings.putIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
- value,
+ if (value) 1 else 2,
UserHandle.USER_CURRENT,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 6fc60f1..52bd424 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -147,7 +147,7 @@
// Trying to open it does nothing.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController, never()).expandWithoutQs();
+ verify(mNotificationPanelViewController, never()).expandShadeToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
verify(mNotificationPanelViewController, never()).expand(anyBoolean());
}
@@ -165,7 +165,7 @@
// Can now be opened.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController).expandWithoutQs();
+ verify(mNotificationPanelViewController).expandShadeToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
verify(mNotificationPanelViewController).expandWithQs();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
index 1cccd65c8..cc6be5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
@@ -92,6 +92,20 @@
}
@Test
+ fun onStylusAdded_internal_updatesNotificationSuppression() {
+ startable.onStylusAdded(STYLUS_DEVICE_ID)
+
+ verify(stylusUsiPowerUi, times(1)).updateSuppression(false)
+ }
+
+ @Test
+ fun onStylusAdded_external_noop() {
+ startable.onStylusAdded(EXTERNAL_DEVICE_ID)
+
+ verifyZeroInteractions(stylusUsiPowerUi)
+ }
+
+ @Test
fun onStylusBluetoothConnected_refreshesNotification() {
startable.onStylusBluetoothConnected(STYLUS_DEVICE_ID, "ANY")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
index 1e81dc7..e1668e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
@@ -36,7 +36,6 @@
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -79,7 +78,7 @@
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf())
whenever(inputManager.getInputDevice(0)).thenReturn(btStylusDevice)
whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
- // whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES")
+ whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES")
stylusUsiPowerUi = StylusUsiPowerUI(contextSpy, notificationManager, inputManager, handler)
broadcastReceiver = stylusUsiPowerUi.receiver
@@ -179,7 +178,6 @@
}
@Test
- @Ignore("TODO(b/257936830): get bt address once input api available")
fun refresh_hasConnectedBluetoothStylus_cancelsNotification() {
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0))
@@ -189,7 +187,6 @@
}
@Test
- @Ignore("TODO(b/257936830): get bt address once input api available")
fun refresh_hasConnectedBluetoothStylus_existingNotification_cancelsNotification() {
stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0))
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeDialogLaunchAnimator.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeDialogLaunchAnimator.kt
index 990db77..f723a9e5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeDialogLaunchAnimator.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeDialogLaunchAnimator.kt
@@ -23,14 +23,20 @@
isUnlocked: Boolean = true,
isShowingAlternateAuthOnUnlock: Boolean = false,
interactionJankMonitor: InteractionJankMonitor = mock(InteractionJankMonitor::class.java),
+ isPredictiveBackQsDialogAnim: Boolean = false,
): DialogLaunchAnimator {
return DialogLaunchAnimator(
- FakeCallback(
- isUnlocked = isUnlocked,
- isShowingAlternateAuthOnUnlock = isShowingAlternateAuthOnUnlock,
- ),
- interactionJankMonitor,
- fakeLaunchAnimator(),
+ callback =
+ FakeCallback(
+ isUnlocked = isUnlocked,
+ isShowingAlternateAuthOnUnlock = isShowingAlternateAuthOnUnlock,
+ ),
+ interactionJankMonitor = interactionJankMonitor,
+ featureFlags =
+ object : AnimationFeatureFlags {
+ override val isPredictiveBackQsDialogAnim = isPredictiveBackQsDialogAnim
+ },
+ launchAnimator = fakeLaunchAnimator(),
isForTesting = true,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
index 4a881a7..fd1b8e9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
@@ -41,7 +41,7 @@
}
override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
- return data.getOrDefault(key, defValues) as? MutableSet<String>?
+ return (data.getOrDefault(key, defValues) as? Set<String>?)?.toMutableSet()
}
override fun getInt(key: String, defValue: Int): Int {
diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml
index 2087b62..41204aa 100644
--- a/packages/VpnDialogs/res/values-ky/strings.xml
+++ b/packages/VpnDialogs/res/values-ky/strings.xml
@@ -29,7 +29,7 @@
<string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. <xliff:g id="VPN_APP_1">%1$s</xliff:g> тармагына кайра туташканга чейин телефонуңуз жалпыга ачык тармакты пайдаланып турат."</string>
<string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. VPN тармагына кайра туташмайынча, Интернет жок болот."</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
- <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN жөндөөлөрүн өзгөртүү"</string>
+ <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN параметрлерин өзгөртүү"</string>
<string name="configure" msgid="4905518375574791375">"Конфигурациялоо"</string>
<string name="disconnect" msgid="971412338304200056">"Ажыратуу"</string>
<string name="open_app" msgid="3717639178595958667">"Колдонмону ачуу"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index f4c6cc3..0926f8a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -314,6 +314,9 @@
void unbindImeLocked(AbstractAccessibilityServiceConnection connection);
void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc);
+
+ void setCurrentUserFocusAppearance(int strokeWidth, int color);
+
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b28ab7a..9b0560c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -28,6 +28,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
import static android.provider.Settings.Secure.CONTRAST_LEVEL;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.CONTRAST_DEFAULT_VALUE;
import static android.view.accessibility.AccessibilityManager.CONTRAST_NOT_SET;
@@ -170,6 +171,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -215,6 +217,9 @@
private static final String SET_PIP_ACTION_REPLACEMENT =
"setPictureInPictureActionReplacingConnection";
+ @VisibleForTesting
+ static final String MENU_SERVICE_RELATIVE_CLASS_NAME = ".AccessibilityMenuService";
+
private static final char COMPONENT_NAME_SEPARATOR = ':';
private static final int OWN_PROCESS_ID = android.os.Process.myPid();
@@ -823,6 +828,95 @@
Context.RECEIVER_EXPORTED);
}
+ /**
+ * Migrates the Accessibility Menu to the version provided by the system build,
+ * if necessary based on presence of the service on the device.
+ */
+ @VisibleForTesting
+ void migrateAccessibilityMenuIfNecessaryLocked(AccessibilityUserState userState) {
+ final Set<ComponentName> menuComponentNames = findA11yMenuComponentNamesLocked();
+ final ComponentName menuOutsideSystem = getA11yMenuOutsideSystem(menuComponentNames);
+ final boolean shouldMigrateToMenuInSystem = menuComponentNames.size() == 2
+ && menuComponentNames.contains(ACCESSIBILITY_MENU_IN_SYSTEM)
+ && menuOutsideSystem != null;
+
+ if (!shouldMigrateToMenuInSystem) {
+ if (menuComponentNames.size() == 1) {
+ // If only one Menu package exists then reset its component to the default state.
+ mPackageManager.setComponentEnabledSetting(
+ menuComponentNames.stream().findFirst().get(),
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ PackageManager.DONT_KILL_APP);
+ }
+ return;
+ }
+
+ // Hide Menu-outside-system so that it does not appear in Settings.
+ mPackageManager.setComponentEnabledSetting(
+ menuOutsideSystem,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ // Migrate the accessibility shortcuts.
+ migrateA11yMenuInSettingLocked(userState,
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, menuOutsideSystem);
+ migrateA11yMenuInSettingLocked(userState,
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, menuOutsideSystem);
+ migrateA11yMenuInSettingLocked(userState,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, menuOutsideSystem);
+ // If Menu-outside-system is currently enabled by the user then automatically
+ // disable it and enable Menu-in-system.
+ migrateA11yMenuInSettingLocked(userState,
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, menuOutsideSystem);
+ }
+
+ /**
+ * Returns all {@link ComponentName}s whose class name ends in {@link
+ * #MENU_SERVICE_RELATIVE_CLASS_NAME}.
+ **/
+ private Set<ComponentName> findA11yMenuComponentNamesLocked() {
+ Set<ComponentName> result = new ArraySet<>();
+ final var flags =
+ PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+ new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId)) {
+ final ComponentName componentName = resolveInfo.serviceInfo.getComponentName();
+ if (componentName.getClassName().endsWith(MENU_SERVICE_RELATIVE_CLASS_NAME)) {
+ result.add(componentName);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the first {@link ComponentName} in the provided set that is not equal to {@link
+ * AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM}.
+ */
+ private static ComponentName getA11yMenuOutsideSystem(Set<ComponentName> menuComponentNames) {
+ Optional<ComponentName> menuOutsideSystem = menuComponentNames.stream().filter(
+ name -> !name.equals(ACCESSIBILITY_MENU_IN_SYSTEM)).findFirst();
+ if (menuOutsideSystem.isEmpty()) {
+ return null;
+ }
+ return menuOutsideSystem.get();
+ }
+
+ /**
+ * Replaces <code>toRemove</code> with {@link AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM}
+ * in the requested setting, if present already.
+ */
+ private void migrateA11yMenuInSettingLocked(AccessibilityUserState userState, String setting,
+ ComponentName toRemove) {
+ mTempComponentNameSet.clear();
+ readComponentNamesFromSettingLocked(setting, userState.mUserId, mTempComponentNameSet);
+ if (mTempComponentNameSet.contains(toRemove)) {
+ mTempComponentNameSet.remove(toRemove);
+ mTempComponentNameSet.add(ACCESSIBILITY_MENU_IN_SYSTEM);
+ persistComponentNamesToSettingLocked(setting, mTempComponentNameSet, userState.mUserId);
+ }
+ }
+
// Called only during settings restore; currently supports only the owner user
// TODO: b/22388012
private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting,
@@ -1592,6 +1686,8 @@
mCurrentUserId = userId;
AccessibilityUserState userState = getCurrentUserStateLocked();
+ migrateAccessibilityMenuIfNecessaryLocked(userState);
+
readConfigurationForUserStateLocked(userState);
mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices);
// Even if reading did not yield change, we have to update
@@ -4876,4 +4972,11 @@
transaction.apply();
transaction.close();
}
+
+ @Override
+ public void setCurrentUserFocusAppearance(int strokeWidth, int color) {
+ synchronized (mLock) {
+ getCurrentUserStateLocked().setFocusAppearanceLocked(strokeWidth, color);
+ }
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index d53a080..df913aa 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -43,6 +43,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.R;
import com.android.server.wm.WindowManagerInternal;
import java.util.Arrays;
@@ -63,6 +64,11 @@
private int mDisplayId;
private List<AccessibilityServiceInfo> mInstalledAndEnabledServices;
+ /** The stroke width of the focus rectangle in pixels */
+ private int mFocusStrokeWidth;
+ /** The color of the focus rectangle */
+ private int mFocusColor;
+
ProxyAccessibilityServiceConnection(
Context context,
ComponentName componentName,
@@ -77,6 +83,10 @@
/* systemActionPerformer= */ null, awm, /* activityTaskManagerService= */ null);
mDisplayId = displayId;
setDisplayTypes(DISPLAY_TYPE_PROXY);
+ mFocusStrokeWidth = mContext.getResources().getDimensionPixelSize(
+ R.dimen.accessibility_focus_highlight_stroke_width);
+ mFocusColor = mContext.getResources().getColor(
+ R.color.accessibility_focus_highlight_color);
}
/**
@@ -203,6 +213,48 @@
}
@Override
+ public void setFocusAppearance(int strokeWidth, int color) {
+ synchronized (mLock) {
+ if (!hasRightsToCurrentUserLocked()) {
+ return;
+ }
+
+ if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+ return;
+ }
+
+ if (getFocusStrokeWidthLocked() == strokeWidth && getFocusColorLocked() == color) {
+ return;
+ }
+
+ mFocusStrokeWidth = strokeWidth;
+ mFocusColor = color;
+ // Sets the appearance data in the A11yUserState for now, since the A11yManagers are not
+ // separated.
+ // TODO(254545943): Separate proxy and non-proxy states so the focus appearance on the
+ // phone is not affected by the appearance of a proxy-ed app.
+ mSystemSupport.setCurrentUserFocusAppearance(mFocusStrokeWidth, mFocusColor);
+ mSystemSupport.onClientChangeLocked(false);
+ }
+ }
+
+ /**
+ * Gets the stroke width of the focus rectangle.
+ * @return The stroke width.
+ */
+ public int getFocusStrokeWidthLocked() {
+ return mFocusStrokeWidth;
+ }
+
+ /**
+ * Gets the color of the focus rectangle.
+ * @return The color.
+ */
+ public int getFocusColorLocked() {
+ return mFocusColor;
+ }
+
+ @Override
public void binderDied() {
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index fed0932..54cdb04 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -178,9 +178,15 @@
if (a11yEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
}
+ for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+ final ProxyAccessibilityServiceConnection proxy =
+ mProxyA11yServiceConnections.valueAt(i);
+ if (proxy.mRequestTouchExplorationMode) {
+ clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+ }
+ }
return clientState;
- // TODO(b/254545943): When A11yManager is separated, include support for other properties
- // like isTouchExplorationEnabled.
+ // TODO(b/254545943): When A11yManager is separated, include support for other properties.
}
/**
diff --git a/services/api/current.txt b/services/api/current.txt
index e66bf4d..a92ccd4 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -46,6 +46,14 @@
}
+package com.android.server.appop {
+
+ public interface AppOpsManagerLocal {
+ method public boolean isUidInForeground(int);
+ }
+
+}
+
package com.android.server.pm {
public interface PackageManagerLocal {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceConfig.java b/services/companion/java/com/android/server/companion/CompanionDeviceConfig.java
new file mode 100644
index 0000000..05f2eea
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion;
+
+import android.provider.DeviceConfig;
+
+/**
+ * Feature flags for companion.
+ */
+public class CompanionDeviceConfig {
+
+ private static final String NAMESPACE_COMPANION = "companion";
+
+ /**
+ * Whether system data syncing for telecom-type data is enabled.
+ */
+ public static final String ENABLE_CONTEXT_SYNC_TELECOM = "enable_context_sync_telecom";
+
+ /**
+ * Returns whether the given flag is currently enabled, with a default value of {@code true}.
+ */
+ public static boolean isEnabled(String flag) {
+ return DeviceConfig.getBoolean(NAMESPACE_COMPANION, flag, /* defaultValue= */ true);
+ }
+
+ /**
+ * Returns whether the given flag is currently enabled.
+ */
+ public static boolean isEnabled(String flag, boolean defaultValue) {
+ return DeviceConfig.getBoolean(NAMESPACE_COMPANION, flag, defaultValue);
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
new file mode 100644
index 0000000..56e777f
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.datatransfer.contextsync;
+
+/** Callback for call metadata syncing. */
+public abstract class CallMetadataSyncCallback {
+
+ abstract void processCallControlAction(int crossDeviceCallId, int callControlAction);
+
+ abstract void requestCrossDeviceSync(int userId);
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
new file mode 100644
index 0000000..077fd2a
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.datatransfer.contextsync;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.telecom.Call;
+import android.telecom.CallAudioState;
+import android.telecom.VideoProfile;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.ByteArrayOutputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+/** Data holder for a telecom call and additional metadata. */
+public class CrossDeviceCall {
+
+ private static final String TAG = "CrossDeviceCall";
+
+ private static final int APP_ICON_BITMAP_DIMENSION = 256;
+
+ private static final AtomicLong sNextId = new AtomicLong(1);
+
+ private final long mId;
+ private final Call mCall;
+ @VisibleForTesting boolean mIsEnterprise;
+ @VisibleForTesting boolean mIsOtt;
+ private String mCallingAppName;
+ private byte[] mCallingAppIcon;
+ private String mCallerDisplayName;
+ private int mStatus = android.companion.Telecom.Call.UNKNOWN_STATUS;
+ private String mContactDisplayName;
+ private boolean mIsMuted;
+ private final Set<Integer> mControls = new HashSet<>();
+
+ public CrossDeviceCall(PackageManager packageManager, Call call,
+ CallAudioState callAudioState) {
+ mId = sNextId.getAndIncrement();
+ mCall = call;
+ final String callingAppPackageName = call != null
+ ? call.getDetails().getAccountHandle().getComponentName().getPackageName() : null;
+ mIsOtt = call != null
+ && (call.getDetails().getCallCapabilities() & Call.Details.PROPERTY_SELF_MANAGED)
+ == Call.Details.PROPERTY_SELF_MANAGED;
+ mIsEnterprise = call != null
+ && (call.getDetails().getCallProperties() & Call.Details.PROPERTY_ENTERPRISE_CALL)
+ == Call.Details.PROPERTY_ENTERPRISE_CALL;
+ try {
+ final ApplicationInfo applicationInfo = packageManager
+ .getApplicationInfo(callingAppPackageName,
+ PackageManager.ApplicationInfoFlags.of(0));
+ mCallingAppName = packageManager.getApplicationLabel(applicationInfo).toString();
+ mCallingAppIcon = renderDrawableToByteArray(
+ packageManager.getApplicationIcon(applicationInfo));
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Could not get application info for package " + callingAppPackageName, e);
+ }
+ mIsMuted = callAudioState != null && callAudioState.isMuted();
+ if (call != null) {
+ updateCallDetails(call.getDetails());
+ }
+ }
+
+ private byte[] renderDrawableToByteArray(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ // Can't recycle the drawable's bitmap, so handle separately
+ final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+ if (bitmap.getWidth() > APP_ICON_BITMAP_DIMENSION
+ || bitmap.getHeight() > APP_ICON_BITMAP_DIMENSION) {
+ // Downscale, as the original drawable bitmap is too large.
+ final Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,
+ APP_ICON_BITMAP_DIMENSION, APP_ICON_BITMAP_DIMENSION, /* filter= */ true);
+ final byte[] renderedBitmap = renderBitmapToByteArray(scaledBitmap);
+ scaledBitmap.recycle();
+ return renderedBitmap;
+ }
+ return renderBitmapToByteArray(bitmap);
+ }
+ final Bitmap bitmap = Bitmap.createBitmap(APP_ICON_BITMAP_DIMENSION,
+ APP_ICON_BITMAP_DIMENSION,
+ Bitmap.Config.ARGB_8888);
+ try {
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ drawable.draw(canvas);
+ } finally {
+ bitmap.recycle();
+ }
+ return renderBitmapToByteArray(bitmap);
+ }
+
+ private byte[] renderBitmapToByteArray(Bitmap bitmap) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream(bitmap.getByteCount());
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
+ return baos.toByteArray();
+ }
+
+ /**
+ * Update the mute state of this call. No-op if the call is not capable of being muted.
+ *
+ * @param isMuted true if the call should be muted, and false if the call should be unmuted.
+ */
+ public void updateMuted(boolean isMuted) {
+ mIsMuted = isMuted;
+ updateCallDetails(mCall.getDetails());
+ }
+
+ /**
+ * Update the state of the call to be ringing silently if it is currently ringing. No-op if the
+ * call is not
+ * currently ringing.
+ */
+ public void updateSilencedIfRinging() {
+ if (mStatus == android.companion.Telecom.Call.RINGING) {
+ mStatus = android.companion.Telecom.Call.RINGING_SILENCED;
+ }
+ mControls.remove(android.companion.Telecom.Call.SILENCE);
+ }
+
+ @VisibleForTesting
+ void updateCallDetails(Call.Details callDetails) {
+ mCallerDisplayName = callDetails.getCallerDisplayName();
+ mContactDisplayName = callDetails.getContactDisplayName();
+ mStatus = convertStateToStatus(callDetails.getState());
+ mControls.clear();
+ if (mStatus == android.companion.Telecom.Call.RINGING
+ || mStatus == android.companion.Telecom.Call.RINGING_SILENCED) {
+ mControls.add(android.companion.Telecom.Call.ACCEPT);
+ mControls.add(android.companion.Telecom.Call.REJECT);
+ if (mStatus == android.companion.Telecom.Call.RINGING) {
+ mControls.add(android.companion.Telecom.Call.SILENCE);
+ }
+ }
+ if (mStatus == android.companion.Telecom.Call.ONGOING
+ || mStatus == android.companion.Telecom.Call.ON_HOLD) {
+ mControls.add(android.companion.Telecom.Call.END);
+ if (callDetails.can(Call.Details.CAPABILITY_HOLD)) {
+ mControls.add(
+ mStatus == android.companion.Telecom.Call.ON_HOLD
+ ? android.companion.Telecom.Call.TAKE_OFF_HOLD
+ : android.companion.Telecom.Call.PUT_ON_HOLD);
+ }
+ }
+ if (mStatus == android.companion.Telecom.Call.ONGOING && callDetails.can(
+ Call.Details.CAPABILITY_MUTE)) {
+ mControls.add(mIsMuted ? android.companion.Telecom.Call.UNMUTE
+ : android.companion.Telecom.Call.MUTE);
+ }
+ }
+
+ private int convertStateToStatus(int callState) {
+ switch (callState) {
+ case Call.STATE_HOLDING:
+ return android.companion.Telecom.Call.ON_HOLD;
+ case Call.STATE_ACTIVE:
+ return android.companion.Telecom.Call.ONGOING;
+ case Call.STATE_RINGING:
+ return android.companion.Telecom.Call.RINGING;
+ case Call.STATE_NEW:
+ case Call.STATE_DIALING:
+ case Call.STATE_DISCONNECTED:
+ case Call.STATE_SELECT_PHONE_ACCOUNT:
+ case Call.STATE_CONNECTING:
+ case Call.STATE_DISCONNECTING:
+ case Call.STATE_PULLING_CALL:
+ case Call.STATE_AUDIO_PROCESSING:
+ case Call.STATE_SIMULATED_RINGING:
+ default:
+ return android.companion.Telecom.Call.UNKNOWN_STATUS;
+ }
+ }
+
+ public long getId() {
+ return mId;
+ }
+
+ public Call getCall() {
+ return mCall;
+ }
+
+ public String getCallingAppName() {
+ return mCallingAppName;
+ }
+
+ public byte[] getCallingAppIcon() {
+ return mCallingAppIcon;
+ }
+
+ /**
+ * Get a human-readable "caller id" to display as the origin of the call.
+ *
+ * @param isAdminBlocked whether there is an admin that has blocked contacts over Bluetooth
+ */
+ public String getReadableCallerId(boolean isAdminBlocked) {
+ if (mIsOtt) {
+ return mCallerDisplayName;
+ }
+ return mIsEnterprise && isAdminBlocked ? mCallerDisplayName : mContactDisplayName;
+ }
+
+ public int getStatus() {
+ return mStatus;
+ }
+
+ public Set<Integer> getControls() {
+ return mControls;
+ }
+
+ void doAccept() {
+ mCall.answer(VideoProfile.STATE_AUDIO_ONLY);
+ }
+
+ void doReject() {
+ if (mStatus == android.companion.Telecom.Call.RINGING) {
+ mCall.reject(Call.REJECT_REASON_DECLINED);
+ }
+ }
+
+ void doEnd() {
+ mCall.disconnect();
+ }
+
+ void doPutOnHold() {
+ mCall.hold();
+ }
+
+ void doTakeOffHold() {
+ mCall.unhold();
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
new file mode 100644
index 0000000..3d8fb7a
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.datatransfer.contextsync;
+
+import android.app.admin.DevicePolicyManager;
+import android.companion.AssociationInfo;
+import android.companion.ContextSyncMessage;
+import android.companion.Telecom;
+import android.companion.Telecom.Call;
+import android.content.Context;
+import android.os.UserHandle;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Monitors connections and sending / receiving of synced data.
+ */
+public class CrossDeviceSyncController {
+
+ private static final String TAG = "CrossDeviceSyncController";
+ private static final int BYTE_ARRAY_SIZE = 64;
+
+ private final Context mContext;
+ private final Callback mCdmCallback;
+ private final Map<Integer, List<AssociationInfo>> mUserIdToAssociationInfo = new HashMap<>();
+ private final Map<Integer, Pair<InputStream, OutputStream>> mAssociationIdToStreams =
+ new HashMap<>();
+ private final Set<Integer> mBlocklist = new HashSet<>();
+
+ private CallMetadataSyncCallback mInCallServiceCallMetadataSyncCallback;
+
+ public CrossDeviceSyncController(Context context, Callback callback) {
+ mContext = context;
+ mCdmCallback = callback;
+ }
+
+ /** Registers the call metadata callback. */
+ public void registerCallMetadataSyncCallback(CallMetadataSyncCallback callback) {
+ mInCallServiceCallMetadataSyncCallback = callback;
+ }
+
+ /** Allow specific associated devices to enable / disable syncing. */
+ public void setSyncEnabled(AssociationInfo associationInfo, boolean enabled) {
+ if (enabled) {
+ if (mBlocklist.contains(associationInfo.getId())) {
+ mBlocklist.remove(associationInfo.getId());
+ openChannel(associationInfo);
+ }
+ } else {
+ if (!mBlocklist.contains(associationInfo.getId())) {
+ mBlocklist.add(associationInfo.getId());
+ closeChannel(associationInfo);
+ }
+ }
+ }
+
+ /**
+ * Opens channels to newly associated devices, and closes channels to newly disassociated
+ * devices.
+ *
+ * TODO(b/265466098): this needs to be limited to just connected devices
+ */
+ public void onAssociationsChanged(int userId, List<AssociationInfo> newAssociationInfoList) {
+ final List<AssociationInfo> existingAssociationInfoList = mUserIdToAssociationInfo.get(
+ userId);
+ // Close channels to newly-disconnected devices.
+ for (AssociationInfo existingAssociationInfo : existingAssociationInfoList) {
+ if (!newAssociationInfoList.contains(existingAssociationInfo) && !mBlocklist.contains(
+ existingAssociationInfo.getId())) {
+ closeChannel(existingAssociationInfo);
+ }
+ }
+ // Open channels to newly-connected devices.
+ for (AssociationInfo newAssociationInfo : newAssociationInfoList) {
+ if (!existingAssociationInfoList.contains(newAssociationInfo) && !mBlocklist.contains(
+ newAssociationInfo.getId())) {
+ openChannel(newAssociationInfo);
+ }
+ }
+ mUserIdToAssociationInfo.put(userId, newAssociationInfoList);
+ }
+
+ private boolean isAdminBlocked(int userId) {
+ return mContext.getSystemService(DevicePolicyManager.class)
+ .getBluetoothContactSharingDisabled(UserHandle.of(userId));
+ }
+
+ /** Stop reading, close streams, and close secure channel. */
+ private void closeChannel(AssociationInfo associationInfo) {
+ // TODO(b/265466098): stop reading from secure channel
+ final Pair<InputStream, OutputStream> streams = mAssociationIdToStreams.get(
+ associationInfo.getId());
+ if (streams != null) {
+ try {
+ if (streams.first != null) {
+ streams.first.close();
+ }
+ if (streams.second != null) {
+ streams.second.close();
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not close streams for association " + associationInfo.getId(),
+ e);
+ }
+ }
+ mCdmCallback.closeSecureChannel(associationInfo.getId());
+ }
+
+ /** Sync initial snapshot and start reading. */
+ private void openChannel(AssociationInfo associationInfo) {
+ final InputStream is = new ByteArrayInputStream(new byte[BYTE_ARRAY_SIZE]);
+ final OutputStream os = new ByteArrayOutputStream(BYTE_ARRAY_SIZE);
+ mAssociationIdToStreams.put(associationInfo.getId(), new Pair<>(is, os));
+ mCdmCallback.createSecureChannel(associationInfo.getId(), is, os);
+ // TODO(b/265466098): only requestSync for this specific association / connection?
+ mInCallServiceCallMetadataSyncCallback.requestCrossDeviceSync(associationInfo.getUserId());
+ // TODO(b/265466098): start reading from secure channel
+ }
+
+ /**
+ * Sync data to associated devices.
+ *
+ * @param userId The user whose data should be synced.
+ * @param calls The full list of current calls for all users.
+ */
+ public void crossDeviceSync(int userId, Collection<CrossDeviceCall> calls) {
+ final boolean isAdminBlocked = isAdminBlocked(userId);
+ for (AssociationInfo associationInfo : mUserIdToAssociationInfo.get(userId)) {
+ final Pair<InputStream, OutputStream> streams = mAssociationIdToStreams.get(
+ associationInfo.getId());
+ final ProtoOutputStream pos = new ProtoOutputStream(streams.second);
+ final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
+ for (CrossDeviceCall call : calls) {
+ final long callsToken = pos.start(Telecom.CALLS);
+ pos.write(Call.ID, call.getId());
+ final long originToken = pos.start(Call.ORIGIN);
+ pos.write(Call.Origin.CALLER_ID, call.getReadableCallerId(isAdminBlocked));
+ pos.write(Call.Origin.APP_ICON, call.getCallingAppIcon());
+ pos.write(Call.Origin.APP_NAME, call.getCallingAppName());
+ pos.end(originToken);
+ pos.write(Call.STATUS, call.getStatus());
+ for (int control : call.getControls()) {
+ pos.write(Call.CONTROLS_AVAILABLE, control);
+ }
+ pos.end(callsToken);
+ }
+ pos.end(telecomToken);
+ pos.flush();
+ }
+ }
+
+ /**
+ * Callback to be implemented by CompanionDeviceManagerService.
+ */
+ public interface Callback {
+ /**
+ * Create a secure channel to send messages.
+ */
+ void createSecureChannel(int associationId, InputStream input, OutputStream output);
+
+ /**
+ * Close the secure channel created previously.
+ */
+ void closeSecureChannel(int associationId);
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 5985ce4..3100277 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -88,7 +88,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
import java.util.function.Consumer;
@@ -114,7 +113,7 @@
private final CameraAccessController mCameraAccessController;
private VirtualAudioController mVirtualAudioController;
@VisibleForTesting
- final Set<Integer> mVirtualDisplayIds = new ArraySet<>();
+ final ArraySet<Integer> mVirtualDisplayIds = new ArraySet<>();
private final OnDeviceCloseListener mOnDeviceCloseListener;
private final IBinder mAppToken;
private final VirtualDeviceParams mParams;
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 47ec80e..f39c32df 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -67,7 +67,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -176,6 +175,11 @@
@VisibleForTesting
void notifyRunningAppsChanged(int deviceId, ArraySet<Integer> uids) {
synchronized (mVirtualDeviceManagerLock) {
+ if (!mVirtualDevices.contains(deviceId)) {
+ Slog.e(TAG, "notifyRunningAppsChanged called for unknown deviceId:" + deviceId
+ + " (maybe it was recently closed?)");
+ return;
+ }
mAppsOnVirtualDevices.put(deviceId, uids);
}
mLocalService.onAppsOnVirtualDeviceChanged();
@@ -466,7 +470,7 @@
}
@Override
- public @NonNull Set<Integer> getDeviceIdsForUid(int uid) {
+ public @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid) {
ArraySet<Integer> result = new ArraySet<>();
synchronized (mVirtualDeviceManagerLock) {
int size = mVirtualDevices.size();
@@ -582,6 +586,20 @@
}
@Override
+ public @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId) {
+ synchronized (mVirtualDeviceManagerLock) {
+ int size = mVirtualDevices.size();
+ for (int i = 0; i < size; i++) {
+ VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
+ if (device.getDeviceId() == deviceId) {
+ return new ArraySet<>(device.mVirtualDisplayIds);
+ }
+ }
+ }
+ return new ArraySet<>();
+ }
+
+ @Override
public void registerVirtualDisplayListener(
@NonNull VirtualDisplayListener listener) {
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 97e9d26..c0bb586 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -156,7 +156,7 @@
"android.hardware.health-V1.0-java", // HIDL
"android.hardware.health-V2.0-java", // HIDL
"android.hardware.health-V2.1-java", // HIDL
- "android.hardware.health-V1-java", // AIDL
+ "android.hardware.health-V2-java", // AIDL
"android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.1-java",
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index a35aa7c..70eeb7f 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -329,11 +329,11 @@
* when the user is first unlocked to update the usage stats package mappings data that might
* be stale or have existed from a restore and belongs to packages that are not installed for
* this user anymore.
- * Note: this is only executed for the system user.
*
+ * @param userId The user to update
* @return {@code true} if the updating was successful, {@code false} otherwise
*/
- public abstract boolean updatePackageMappingsData();
+ public abstract boolean updatePackageMappingsData(@UserIdInt int userId);
/**
* Listener interface for usage events.
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index fce44f5..8f594a5 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -27,15 +27,20 @@
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.compat.annotation.ChangeId;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApexStagedEvent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IBackgroundInstallControlService;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.InstallSourceInfo;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
@@ -51,6 +56,7 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -62,6 +68,7 @@
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.PackageUtils;
import android.util.Slog;
@@ -131,13 +138,17 @@
// used for indicating newly installed MBAs that are updated (but unused currently)
static final int MBA_STATUS_UPDATED_NEW_INSTALL = 4;
+ @VisibleForTesting
+ static final String KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION =
+ "enable_biometric_property_verification";
+
private static final boolean DEBUG = false; // toggle this for local debug
private final Context mContext;
private String mVbmetaDigest;
// the system time (in ms) the last measurement was taken
private long mMeasurementsLastRecordedMs;
- private PackageManagerInternal mPackageManagerInternal;
+ private BiometricLogger mBiometricLogger;
/**
* Guards whether or not measurements of MBA to be performed. When this change is enabled,
@@ -1049,13 +1060,55 @@
}
private final BinaryTransparencyServiceImpl mServiceImpl;
+ /**
+ * A wrapper of {@link FrameworkStatsLog} for easier testing
+ */
+ @VisibleForTesting
+ public static class BiometricLogger {
+ private static final String TAG = "BiometricLogger";
+
+ private static final BiometricLogger sInstance = new BiometricLogger();
+
+ private BiometricLogger() {}
+
+ public static BiometricLogger getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * A wrapper of {@link FrameworkStatsLog}
+ *
+ * @param sensorId The sensorId of the biometric to be logged
+ * @param modality The modality of the biometric
+ * @param sensorType The sensor type of the biometric
+ * @param sensorStrength The sensor strength of the biometric
+ * @param componentId The component Id of a component of the biometric
+ * @param hardwareVersion The hardware version of a component of the biometric
+ * @param firmwareVersion The firmware version of a component of the biometric
+ * @param serialNumber The serial number of a component of the biometric
+ * @param softwareVersion The software version of a component of the biometric
+ */
+ public void logStats(int sensorId, int modality, int sensorType, int sensorStrength,
+ String componentId, String hardwareVersion, String firmwareVersion,
+ String serialNumber, String softwareVersion) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_PROPERTIES_COLLECTED,
+ sensorId, modality, sensorType, sensorStrength, componentId, hardwareVersion,
+ firmwareVersion, serialNumber, softwareVersion);
+ }
+ }
+
public BinaryTransparencyService(Context context) {
+ this(context, BiometricLogger.getInstance());
+ }
+
+ @VisibleForTesting
+ BinaryTransparencyService(Context context, BiometricLogger biometricLogger) {
super(context);
mContext = context;
mServiceImpl = new BinaryTransparencyServiceImpl();
mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED;
mMeasurementsLastRecordedMs = 0;
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mBiometricLogger = biometricLogger;
}
/**
@@ -1070,28 +1123,6 @@
} catch (Throwable t) {
Slog.e(TAG, "Failed to start BinaryTransparencyService.", t);
}
-
- // register a package observer to detect updates to preloads
- mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() {
- @Override
- public void onPackageChanged(String packageName, int uid) {
- // check if the updated package is a preloaded app.
- PackageManager pm = mContext.getPackageManager();
- try {
- pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(
- PackageManager.MATCH_FACTORY_ONLY));
- } catch (PackageManager.NameNotFoundException e) {
- // this means that this package is not a preloaded app
- return;
- }
-
- Slog.d(TAG, "Preload " + packageName + " was updated. Scheduling measurement...");
- UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
- BinaryTransparencyService.this);
- }
- });
-
- // TODO(b/264428429): Register observer for updates to APEXs.
}
/**
@@ -1123,6 +1154,8 @@
Slog.i(TAG, "Scheduling measurements to be taken.");
UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
BinaryTransparencyService.this);
+
+ registerAllPackageUpdateObservers();
}
}
@@ -1301,7 +1334,7 @@
// Note: none of the component info is a device identifier since every device of a given
// model and build share the same biometric system info (see b/216195167)
for (ComponentInfo componentInfo : prop.getComponentInfo()) {
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_PROPERTIES_COLLECTED,
+ mBiometricLogger.logStats(
sensorId,
modality,
sensorType,
@@ -1314,7 +1347,19 @@
}
}
- private void collectBiometricProperties() {
+ @VisibleForTesting
+ void collectBiometricProperties() {
+ // Check the flag to determine whether biometric property verification is enabled. It's
+ // disabled by default.
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BIOMETRICS,
+ KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, false)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Do not collect/verify biometric properties. Feature disabled by "
+ + "DeviceConfig");
+ }
+ return;
+ }
+
PackageManager pm = mContext.getPackageManager();
FingerprintManager fpManager = null;
FaceManager faceManager = null;
@@ -1354,6 +1399,126 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
}
+ /**
+ * Listen for APK updates.
+ *
+ * There are two ways available to us to do this:
+ * 1. Register an observer using
+ * {@link PackageManagerInternal#getPackageList(PackageManagerInternal.PackageListObserver)}.
+ * 2. Register broadcast receivers, listening to either {@code ACTION_PACKAGE_ADDED} or
+ * {@code ACTION_PACKAGE_REPLACED}.
+ *
+ * After experimentation, we found that Option #1 does not catch updates to non-staged APEXs.
+ * Thus, we are implementing Option #2 here. More specifically, listening to
+ * {@link Intent#ACTION_PACKAGE_ADDED} allows us to capture all events we care about.
+ *
+ * We did not use {@link Intent#ACTION_PACKAGE_REPLACED} because it unfortunately does not
+ * detect updates to non-staged APEXs. Thus, we rely on {@link Intent#EXTRA_REPLACING} to
+ * filter out new installation from updates instead.
+ */
+ private void registerApkAndNonStagedApexUpdateListener() {
+ Slog.d(TAG, "Registering APK & Non-Staged APEX updates...");
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addDataScheme("package"); // this is somehow necessary
+ mContext.registerReceiver(new PackageUpdatedReceiver(), filter);
+ }
+
+ /**
+ * Listen for staged-APEX updates.
+ *
+ * This method basically covers cases that are not caught by
+ * {@link #registerApkAndNonStagedApexUpdateListener()}, namely updates to APEXs that are staged
+ * for the subsequent reboot.
+ */
+ private void registerStagedApexUpdateObserver() {
+ Slog.d(TAG, "Registering APEX updates...");
+ IPackageManagerNative iPackageManagerNative = IPackageManagerNative.Stub.asInterface(
+ ServiceManager.getService("package_native"));
+ if (iPackageManagerNative == null) {
+ Slog.e(TAG, "IPackageManagerNative is null");
+ return;
+ }
+
+ try {
+ iPackageManagerNative.registerStagedApexObserver(new IStagedApexObserver.Stub() {
+ @Override
+ public void onApexStaged(ApexStagedEvent event) throws RemoteException {
+ Slog.d(TAG, "A new APEX has been staged for update. There are currently "
+ + event.stagedApexModuleNames.length + " APEX(s) staged for update. "
+ + "Scheduling measurement...");
+ UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
+ BinaryTransparencyService.this);
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register a StagedApexObserver.");
+ }
+ }
+
+ private boolean isPackagePreloaded(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(
+ PackageManager.MATCH_FACTORY_ONLY));
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isPackageAnApex(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ PackageInfo packageInfo = pm.getPackageInfo(packageName,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
+ return packageInfo.isApex;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private class PackageUpdatedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) {
+ return;
+ }
+
+ Uri data = intent.getData();
+ if (data == null) {
+ Slog.e(TAG, "Shouldn't happen: intent data is null!");
+ return;
+ }
+
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ Slog.d(TAG, "Not an update. Skipping...");
+ return;
+ }
+
+ String packageName = data.getSchemeSpecificPart();
+ // now we've got to check what package is this
+ if (isPackagePreloaded(packageName) || isPackageAnApex(packageName)) {
+ Slog.d(TAG, packageName + " was updated. Scheduling measurement...");
+ UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
+ BinaryTransparencyService.this);
+ }
+ }
+ }
+
+ /**
+ * Register observers for APK and APEX updates. The current implementation breaks this process
+ * into 2 cases/methods because PackageManager does not offer a unified interface to register
+ * for all package updates in a universal and comprehensive manner.
+ * Thus, the observers will be invoked when either
+ * i) APK or non-staged APEX update; or
+ * ii) APEX staging happens.
+ * This will then be used as signals to schedule measurement for the relevant binaries.
+ */
+ private void registerAllPackageUpdateObservers() {
+ registerApkAndNonStagedApexUpdateListener();
+ registerStagedApexUpdateObserver();
+ }
+
private String translateContentDigestAlgorithmIdToString(int algorithmId) {
switch (algorithmId) {
case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index ff75796..4854c37 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -321,6 +321,7 @@
private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>();
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
+ private final ArraySet<String> mAutomaticRollbackDenylistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
// A map from package name of vendor APEXes that can be updated to an installer package name
// allowed to install updates for it.
@@ -461,6 +462,10 @@
return mRollbackWhitelistedPackages;
}
+ public Set<String> getAutomaticRollbackDenylistedPackages() {
+ return mAutomaticRollbackDenylistedPackages;
+ }
+
public Set<String> getWhitelistedStagedInstallers() {
return mWhitelistedStagedInstallers;
}
@@ -1356,6 +1361,16 @@
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "automatic-rollback-denylisted-app": {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mAutomaticRollbackDenylistedPackages.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
case "whitelisted-staged-installer": {
if (allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7b8ca91..cfd22e8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2250,14 +2250,19 @@
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
+ boolean preciseCallStateChanged = false;
mRingingCallState[phoneId] = ringingCallState;
mForegroundCallState[phoneId] = foregroundCallState;
mBackgroundCallState[phoneId] = backgroundCallState;
- mPreciseCallState[phoneId] = new PreciseCallState(
+ PreciseCallState preciseCallState = new PreciseCallState(
ringingCallState, foregroundCallState,
backgroundCallState,
DisconnectCause.NOT_VALID,
PreciseDisconnectCause.NOT_VALID);
+ if (!preciseCallState.equals(mPreciseCallState[phoneId])) {
+ preciseCallStateChanged = true;
+ mPreciseCallState[phoneId] = preciseCallState;
+ }
boolean notifyCallState = true;
if (mCallQuality == null) {
log("notifyPreciseCallState: mCallQuality is null, "
@@ -2271,6 +2276,8 @@
mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mCallQuality[phoneId] = createCallQuality();
}
+ List<CallState> prevCallStateList = new ArrayList<>();
+ prevCallStateList.addAll(mCallStateLists.get(phoneId));
mCallStateLists.get(phoneId).clear();
if (foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
&& foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
@@ -2330,6 +2337,9 @@
}
mCallStateLists.get(phoneId).add(builder.build());
}
+ if (prevCallStateList.equals(mCallStateLists.get(phoneId))) {
+ notifyCallState = false;
+ }
boolean hasOngoingCall = false;
for (CallState cs : mCallStateLists.get(phoneId)) {
if (cs.getCallState() != PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED) {
@@ -2343,23 +2353,30 @@
}
}
- for (Record r : mRecords) {
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)
- && idMatch(r, subId, phoneId)) {
- try {
- r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ if (preciseCallStateChanged) {
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
- if (notifyCallState && r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
- && idMatch(r, subId, phoneId)) {
- try {
- r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ }
+
+ if (notifyCallState) {
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 41437d1..73bb8d7 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -206,6 +206,7 @@
import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.LowMemDetector.MemFactor;
+import com.android.server.am.ServiceRecord.ShortFgsInfo;
import com.android.server.pm.KnownPackages;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -1985,7 +1986,7 @@
foregroundServiceType == FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
final boolean isOldTypeShortFgsAndTimedOut = r.shouldTriggerShortFgsTimeout();
- if (isOldTypeShortFgs || isNewTypeShortFgs) {
+ if (r.isForeground && (isOldTypeShortFgs || isNewTypeShortFgs)) {
if (DEBUG_SHORT_SERVICE) {
Slog.i(TAG_SERVICE, String.format(
"FGS type changing from %x%s to %x: %s",
@@ -2021,10 +2022,8 @@
} else {
// FGS type is changing from SHORT_SERVICE to another type when
// an app is allowed to start FGS, so this will succeed.
- // The timeout will stop -- we actually don't cancel the handler
- // events, but they'll be ignored if the service type is not
- // SHORT_SERVICE.
- // TODO(short-service) Let's actaully cancel the handler events.
+ // The timeout will stop later, in
+ // maybeUpdateShortFgsTrackingLocked().
}
} else {
// We catch this case later, in the
@@ -2226,7 +2225,7 @@
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
- maybeStartShortFgsTimeoutAndUpdateShortFgsInfoLocked(r,
+ maybeUpdateShortFgsTrackingLocked(r,
extendShortServiceTimeout);
} else {
if (DEBUG_FOREGROUND_SERVICE) {
@@ -3022,11 +3021,17 @@
}
/**
- * If {@code sr} is of a short-fgs, start a short-FGS timeout.
+ * Update a {@link ServiceRecord}'s {@link ShortFgsInfo} as needed, and also start
+ * a timeout as needed.
+ *
+ * If the {@link ServiceRecord} is not a short-FGS, then we'll stop the timeout and clear
+ * the {@link ShortFgsInfo}.
*/
- private void maybeStartShortFgsTimeoutAndUpdateShortFgsInfoLocked(ServiceRecord sr,
+ private void maybeUpdateShortFgsTrackingLocked(ServiceRecord sr,
boolean extendTimeout) {
if (!sr.isShortFgs()) {
+ sr.clearShortFgsInfo(); // Just in case we have it.
+ unscheduleShortFgsTimeoutLocked(sr);
return;
}
if (DEBUG_SHORT_SERVICE) {
@@ -3035,29 +3040,32 @@
if (extendTimeout || !sr.hasShortFgsInfo()) {
sr.setShortFgsInfo(SystemClock.uptimeMillis());
+
+ // We'll restart the timeout.
+ unscheduleShortFgsTimeoutLocked(sr);
+
+ final Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
+ mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getTimeoutTime());
} else {
// We only (potentially) update the start command, start count, but not the timeout
// time.
+ // In this case, we keep the existing timeout running.
sr.getShortFgsInfo().update();
}
- unscheduleShortFgsTimeoutLocked(sr); // Do it just in case
-
- final Message msg = mAm.mHandler.obtainMessage(
- ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
- mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getTimeoutTime());
}
/**
* Stop the timeout for a ServiceRecord, if it's of a short-FGS.
*/
private void maybeStopShortFgsTimeoutLocked(ServiceRecord sr) {
+ sr.clearShortFgsInfo(); // Always clear, just in case.
if (!sr.isShortFgs()) {
return;
}
if (DEBUG_SHORT_SERVICE) {
Slog.i(TAG_SERVICE, "Stop short FGS timeout: " + sr);
}
- sr.clearShortFgsInfo();
unscheduleShortFgsTimeoutLocked(sr);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 70f07a9..523e0f0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -951,7 +951,7 @@
"short_fgs_timeout_duration";
/** @see #KEY_SHORT_FGS_TIMEOUT_DURATION */
- static final long DEFAULT_SHORT_FGS_TIMEOUT_DURATION = 60_000;
+ static final long DEFAULT_SHORT_FGS_TIMEOUT_DURATION = 3 * 60_000;
/** @see #KEY_SHORT_FGS_TIMEOUT_DURATION */
public volatile long mShortFgsTimeoutDuration = DEFAULT_SHORT_FGS_TIMEOUT_DURATION;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index de87a0c..5f27841 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8432,15 +8432,13 @@
t.traceEnd();
}
+ boolean isBootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
+
// Some systems - like automotive - will explicitly unlock system user then switch
- // to a secondary user. Hence, we don't want to send duplicate broadcasts for
- // the system user here.
+ // to a secondary user.
// TODO(b/242195409): this workaround shouldn't be necessary once we move
// the headless-user start logic to UserManager-land.
- final boolean isBootingSystemUser = (currentUserId == UserHandle.USER_SYSTEM)
- && !UserManager.isHeadlessSystemUserMode();
-
- if (isBootingSystemUser) {
+ if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
t.traceBegin("startHomeOnAllDisplays");
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
t.traceEnd();
@@ -8452,6 +8450,10 @@
if (isBootingSystemUser) {
+ // Need to send the broadcasts for the system user here because
+ // UserController#startUserInternal will not send them for the system user starting,
+ // It checks if the user state already exists, which is always the case for the
+ // system user.
t.traceBegin("sendUserStartBroadcast");
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -17842,11 +17844,9 @@
*/
synchronized (wmLock) {
if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
- setDebugApp(aInfo.processName, true, false);
- }
-
- if ((startFlags & ActivityManager.START_FLAG_DEBUG_SUSPEND) != 0) {
- setDebugApp(aInfo.processName, true, false, true);
+ boolean suspend =
+ (startFlags & ActivityManager.START_FLAG_DEBUG_SUSPEND) != 0;
+ setDebugApp(aInfo.processName, true, false, suspend);
}
if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index f54e2b0..410bc41 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -118,7 +118,7 @@
private static final int FREEZE_BINDER_TIMEOUT_MS = 100;
// Defaults for phenotype flags.
- @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
+ @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
@VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
@VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_ALL;
@VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE;
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 85de637..8d3c21e 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -57,6 +57,7 @@
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -87,7 +88,6 @@
import com.android.server.LocalServices;
import com.android.server.RescueParty;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.UserManagerService;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
@@ -186,7 +186,7 @@
checkTime(startTime, "getContentProviderImpl: getProviderByName");
- UserManagerService userManagerService = UserManagerService.getInstance();
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
/*
For clone user profile and allowed authority, skipping finding provider and redirecting
@@ -196,8 +196,10 @@
used and redirect to owner user's MediaProvider.
*/
//todo(b/236121588) MediaProvider should not be installed in clone profile.
- if (!isAuthorityRedirectedForCloneProfile(name)
- || !userManagerService.isMediaSharedWithParent(userId)) {
+ final UserProperties userProps = umInternal.getUserProperties(userId);
+ final boolean isMediaSharedWithParent =
+ userProps != null && userProps.isMediaSharedWithParent();
+ if (!isAuthorityRedirectedForCloneProfile(name) || !isMediaSharedWithParent) {
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
}
@@ -215,9 +217,7 @@
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else if (isAuthorityRedirectedForCloneProfile(name)) {
- if (userManagerService.isMediaSharedWithParent(userId)) {
- UserManagerInternal umInternal = LocalServices.getService(
- UserManagerInternal.class);
+ if (isMediaSharedWithParent) {
userId = umInternal.getProfileParentId(userId);
checkCrossUser = false;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 81655cf..114e2c1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -143,6 +143,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* All of the code required to compute proc states and oom_adj values.
@@ -743,6 +744,45 @@
queue.offer(provider);
provider.mState.setReachable(true);
}
+ // See if this process has any corresponding SDK sandbox processes running, and if so
+ // scan them as well.
+ final List<ProcessRecord> sdkSandboxes =
+ mProcessList.getSdkSandboxProcessesForAppLocked(pr.uid);
+ final int numSdkSandboxes = sdkSandboxes != null ? sdkSandboxes.size() : 0;
+ for (int i = numSdkSandboxes - 1; i >= 0; i--) {
+ ProcessRecord sdkSandbox = sdkSandboxes.get(i);
+ containsCycle |= sdkSandbox.mState.isReachable();
+ if (sdkSandbox.mState.isReachable()) {
+ continue;
+ }
+ queue.offer(sdkSandbox);
+ sdkSandbox.mState.setReachable(true);
+ }
+ // If this process is a sandbox itself, also scan the app on whose behalf its running
+ if (pr.isSdkSandbox) {
+ for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) {
+ ServiceRecord s = psr.getRunningServiceAt(is);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+ s.getConnections();
+ for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
+ for (int i = clist.size() - 1; i >= 0; i--) {
+ ConnectionRecord cr = clist.get(i);
+ ProcessRecord attributedApp = cr.binding.attributedClient;
+ if (attributedApp == null || attributedApp == pr
+ || ((attributedApp.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ)
+ && (attributedApp.mState.getMaxAdj() < FOREGROUND_APP_ADJ))) {
+ continue;
+ }
+ if (attributedApp.mState.isReachable()) {
+ continue;
+ }
+ queue.offer(attributedApp);
+ attributedApp.mState.setReachable(true);
+ }
+ }
+ }
+ }
}
int size = processes.size();
@@ -2131,6 +2171,11 @@
boolean trackedProcState = false;
ProcessRecord client = cr.binding.client;
+ if (app.isSdkSandbox && cr.binding.attributedClient != null) {
+ // For SDK sandboxes, use the attributed client (eg the app that
+ // requested the sandbox)
+ client = cr.binding.attributedClient;
+ }
final ProcessStateRecord cstate = client.mState;
if (computeClients) {
computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now,
@@ -2377,12 +2422,12 @@
state.setAdjType(adjType);
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE);
- state.setAdjSource(cr.binding.client);
+ state.setAdjSource(client);
state.setAdjSourceProcState(clientProcState);
state.setAdjTarget(s.instanceName);
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
- + ": " + app + ", due to " + cr.binding.client
+ + ": " + app + ", due to " + client
+ " adj=" + adj + " procState="
+ ProcessList.makeProcStateString(procState));
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 43075bc..14ecf9f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -32,6 +32,7 @@
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.Overridable;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -65,6 +66,7 @@
/** If enabled BAL are prevented by default in applications targeting U and later. */
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ @Overridable
private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER = 244637991;
private static final String ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER =
"enable_default_rescind_bal_privileges_from_pending_intent_sender";
@@ -450,16 +452,11 @@
resolvedType = key.requestResolvedType;
}
- // Apply any launch flags from the ActivityOptions. This is used only by SystemUI
- // to ensure that we can launch the pending intent with a consistent launch mode even
- // if the provided PendingIntent is immutable (ie. to force an activity to launch into
- // a new task, or to launch multiple instances if supported by the app)
+ // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
+ // can specify a consistent launch mode even if the PendingIntent is immutable
final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
- // TODO(b/254490217): Move this check into SafeActivityOptions
- if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) {
- finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
- }
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
}
// Extract options before clearing calling identity
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 9bb63d3..58a47d7 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -49,6 +49,7 @@
import com.android.internal.annotations.CompositeRWLock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.expresslog.Counter;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.anr.AnrLatencyTracker;
@@ -260,6 +261,28 @@
mDialogController = new ErrorDialogController(app);
}
+ @GuardedBy("mService")
+ boolean skipAnrLocked(String annotation) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mService.mAtmInternal.isShuttingDown()) {
+ Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
+ return true;
+ } else if (isNotResponding()) {
+ Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
+ return true;
+ } else if (isCrashing()) {
+ Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
+ return true;
+ } else if (mApp.isKilledByAm()) {
+ Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
+ return true;
+ } else if (mApp.isKilled()) {
+ Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
+ return true;
+ }
+ return false;
+ }
+
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, TimeoutRecord timeoutRecord,
@@ -303,26 +326,10 @@
// Store annotation here as instance above will not be hit on all paths.
setAnrAnnotation(annotation);
- // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
- if (mService.mAtmInternal.isShuttingDown()) {
- Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
+ Counter.logIncrement("stability_anr.value_total_anrs");
+ if (skipAnrLocked(annotation)) {
latencyTracker.anrSkippedProcessErrorStateRecordAppNotResponding();
- return;
- } else if (isNotResponding()) {
- Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
- latencyTracker.anrSkippedProcessErrorStateRecordAppNotResponding();
- return;
- } else if (isCrashing()) {
- Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
- latencyTracker.anrSkippedProcessErrorStateRecordAppNotResponding();
- return;
- } else if (mApp.isKilledByAm()) {
- Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
- latencyTracker.anrSkippedProcessErrorStateRecordAppNotResponding();
- return;
- } else if (mApp.isKilled()) {
- Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
- latencyTracker.anrSkippedProcessErrorStateRecordAppNotResponding();
+ Counter.logIncrement("stability_anr.value_skipped_anrs");
return;
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3a40fc7..04c0d64 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -485,6 +485,12 @@
final ProcessMap<AppZygote> mAppZygotes = new ProcessMap<AppZygote>();
/**
+ * The currently running SDK sandbox processes for a uid.
+ */
+ @GuardedBy("mService")
+ final SparseArray<ArrayList<ProcessRecord>> mSdkSandboxes = new SparseArray<>();
+
+ /**
* Managees the {@link android.app.ApplicationExitInfo} records.
*/
@GuardedBy("mAppExitInfoTracker")
@@ -2990,6 +2996,14 @@
if (proc.isolated) {
mIsolatedProcesses.put(proc.uid, proc);
}
+ if (proc.isSdkSandbox) {
+ ArrayList<ProcessRecord> sdkSandboxes = mSdkSandboxes.get(proc.uid);
+ if (sdkSandboxes == null) {
+ sdkSandboxes = new ArrayList<>();
+ }
+ sdkSandboxes.add(proc);
+ mSdkSandboxes.put(Process.getAppUidForSdkSandboxUid(proc.uid), sdkSandboxes);
+ }
}
@GuardedBy("mService")
@@ -3030,6 +3044,19 @@
return ret;
}
+ /**
+ * Returns the associated SDK sandbox processes for a UID. Note that this does
+ * NOT return a copy, so callers should not modify the result, or use it outside
+ * of the lock scope.
+ *
+ * @param uid UID to return sansdbox processes for
+ */
+ @Nullable
+ @GuardedBy("mService")
+ List<ProcessRecord> getSdkSandboxProcessesForAppLocked(int uid) {
+ return mSdkSandboxes.get(uid);
+ }
+
@GuardedBy("mService")
ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
boolean isolated, int isolatedUid, boolean isSdkSandbox, int sdkSandboxUid,
@@ -3135,6 +3162,16 @@
if (record != null && record.appZygote) {
removeProcessFromAppZygoteLocked(record);
}
+ if (record != null && record.isSdkSandbox) {
+ final int appUid = Process.getAppUidForSdkSandboxUid(uid);
+ final ArrayList<ProcessRecord> sdkSandboxesForUid = mSdkSandboxes.get(appUid);
+ if (sdkSandboxesForUid != null) {
+ sdkSandboxesForUid.remove(record);
+ if (sdkSandboxesForUid.size() == 0) {
+ mSdkSandboxes.remove(appUid);
+ }
+ }
+ }
mAppsInBackgroundRestricted.remove(record);
return old;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 67166b8..8ce9889 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1457,8 +1457,7 @@
}
private boolean shouldStartWithParent(UserInfo user) {
- final UserProperties properties = mInjector.getUserManagerInternal()
- .getUserProperties(user.id);
+ final UserProperties properties = getUserProperties(user.id);
return (properties != null && properties.getStartWithParent())
&& !user.isQuietModeEnabled();
}
@@ -2773,6 +2772,10 @@
return mInjector.getUserManager().getUserInfo(userId);
}
+ private @Nullable UserProperties getUserProperties(@UserIdInt int userId) {
+ return mInjector.getUserManagerInternal().getUserProperties(userId);
+ }
+
int[] getUserIds() {
return mInjector.getUserManager().getUserIds();
}
@@ -2903,7 +2906,8 @@
if (getStartedUserState(userId) == null) {
return false;
}
- if (!mInjector.getUserManager().isCredentialSharableWithParent(userId)) {
+ final UserProperties properties = getUserProperties(userId);
+ if (properties == null || !properties.isCredentialShareableWithParent()) {
return false;
}
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index d195103..893c8b5 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -40,6 +40,7 @@
import android.app.GameState;
import android.app.IGameManagerService;
import android.app.IGameModeListener;
+import android.app.IUidObserver;
import android.app.StatsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -165,38 +166,19 @@
private final ArrayMap<IGameModeListener, Integer> mGameModeListeners = new ArrayMap<>();
@Nullable
private final GameServiceController mGameServiceController;
+ private final Object mUidObserverLock = new Object();
+ @VisibleForTesting
+ @Nullable
+ final UidObserver mUidObserver;
+ @GuardedBy("mUidObserverLock")
+ private final Set<Integer> mForegroundGameUids = new HashSet<>();
public GameManagerService(Context context) {
this(context, createServiceThread().getLooper());
}
GameManagerService(Context context, Looper looper) {
- mContext = context;
- mHandler = new SettingsHandler(looper);
- mPackageManager = mContext.getPackageManager();
- mUserManager = mContext.getSystemService(UserManager.class);
- mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mSystemDir = new File(Environment.getDataDirectory(), "system");
- mSystemDir.mkdirs();
- FileUtils.setPermissions(mSystemDir.toString(),
- FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
- -1, -1);
- mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
- GAME_MODE_INTERVENTION_LIST_FILE_NAME));
- FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
- FileUtils.S_IRUSR | FileUtils.S_IWUSR
- | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
- -1, -1);
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
- mGameServiceController = new GameServiceController(
- context, BackgroundThread.getExecutor(),
- new GameServiceProviderSelectorImpl(
- context.getResources(),
- context.getPackageManager()),
- new GameServiceProviderInstanceFactoryImpl(context));
- } else {
- mGameServiceController = null;
- }
+ this(context, looper, Environment.getDataDirectory());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -227,6 +209,14 @@
} else {
mGameServiceController = null;
}
+ mUidObserver = new UidObserver();
+ try {
+ ActivityManager.getService().registerUidObserver(mUidObserver,
+ ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not register UidObserver");
+ }
}
@Override
@@ -2152,4 +2142,66 @@
* load dynamic library for frame rate overriding JNI calls
*/
private static native void nativeSetOverrideFrameRate(int uid, float frameRate);
+
+ final class UidObserver extends IUidObserver.Stub {
+ @Override
+ public void onUidIdle(int uid, boolean disabled) {}
+
+ @Override
+ public void onUidGone(int uid, boolean disabled) {
+ synchronized (mUidObserverLock) {
+ disableGameMode(uid);
+ }
+ }
+
+ @Override
+ public void onUidActive(int uid) {}
+
+ @Override
+ public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
+ synchronized (mUidObserverLock) {
+ if (ActivityManager.isProcStateBackground(procState)) {
+ disableGameMode(uid);
+ return;
+ }
+
+ final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+ if (packages == null || packages.length == 0) {
+ return;
+ }
+
+ final int userId = mContext.getUserId();
+ if (!Arrays.stream(packages).anyMatch(p -> isPackageGame(p, userId))) {
+ return;
+ }
+
+ if (mForegroundGameUids.isEmpty()) {
+ Slog.v(TAG, "Game power mode ON (process state was changed to foreground)");
+ mPowerManagerInternal.setPowerMode(Mode.GAME, true);
+ }
+ mForegroundGameUids.add(uid);
+ }
+ }
+
+ private void disableGameMode(int uid) {
+ synchronized (mUidObserverLock) {
+ if (!mForegroundGameUids.contains(uid)) {
+ return;
+ }
+ mForegroundGameUids.remove(uid);
+ if (!mForegroundGameUids.isEmpty()) {
+ return;
+ }
+ Slog.v(TAG,
+ "Game power mode OFF (process remomved or state changed to background)");
+ mPowerManagerInternal.setPowerMode(Mode.GAME, false);
+ }
+ }
+
+ @Override
+ public void onUidCachedChanged(int uid, boolean cached) {}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {}
+ }
}
diff --git a/services/core/java/com/android/server/appop/AppOpsManagerLocal.java b/services/core/java/com/android/server/appop/AppOpsManagerLocal.java
new file mode 100644
index 0000000..a665896
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsManagerLocal.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import android.annotation.SystemApi;
+
+/**
+ * In-process app ops API for mainline modules.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface AppOpsManagerLocal {
+
+ /**
+ * Determines if the UID is in foreground in the same way as how foreground runtime
+ * permissions work.
+ *
+ * @return Returns {@code true} if the given UID is in the foreground.
+ */
+ boolean isUidInForeground(int uid);
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 9c6cae3..c50f2b7 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -978,6 +978,7 @@
public void publish() {
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
+ LocalServices.addService(AppOpsManagerLocal.class, new AppOpsManagerLocalImpl());
}
/** Handler for work when packages are removed or updated */
@@ -6138,6 +6139,15 @@
}
}
+ private final class AppOpsManagerLocalImpl implements AppOpsManagerLocal {
+ @Override
+ public boolean isUidInForeground(int uid) {
+ synchronized (AppOpsService.this) {
+ return mUidStateTracker.isUidInForeground(uid);
+ }
+ }
+ }
+
private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
@Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
synchronized (AppOpsService.this) {
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
index 742bf4b..18ea8cf 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
@@ -89,6 +89,11 @@
int getUidState(int uid);
/**
+ * Determines if the uid is in foreground.
+ */
+ boolean isUidInForeground(int uid);
+
+ /**
* Given a uid, code, and mode, resolve any foregroundness to MODE_IGNORED or MODE_ALLOWED
*/
int evalMode(int uid, int code, int mode);
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 5114bd5..49279d4 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -24,8 +24,10 @@
import static android.app.ActivityManager.ProcessCapability;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
@@ -124,60 +126,32 @@
@Override
public int evalMode(int uid, int code, int mode) {
- if (mode != AppOpsManager.MODE_FOREGROUND) {
+ if (mode != MODE_FOREGROUND) {
return mode;
}
- int uidStateValue;
- int capability;
- boolean visibleAppWidget;
- boolean pendingTop;
- boolean tempAllowlist;
- uidStateValue = getUidState(uid);
- capability = getUidCapability(uid);
- visibleAppWidget = getUidVisibleAppWidget(uid);
- pendingTop = mActivityManagerInternal.isPendingTopUid(uid);
- tempAllowlist = mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid);
+ int uidState = getUidState(uid);
+ int uidCapability = getUidCapability(uid);
+ int result = evalModeInternal(uid, code, uidState, uidCapability);
- int result = evalMode(uidStateValue, code, mode, capability, visibleAppWidget, pendingTop,
- tempAllowlist);
- mEventLog.logEvalForegroundMode(uid, uidStateValue, capability, code, result);
+ mEventLog.logEvalForegroundMode(uid, uidState, uidCapability, code, result);
return result;
}
- private static int evalMode(int uidState, int code, int mode, int capability,
- boolean appWidgetVisible, boolean pendingTop, boolean tempAllowlist) {
- if (mode != AppOpsManager.MODE_FOREGROUND) {
- return mode;
- }
+ private int evalModeInternal(int uid, int code, int uidState, int uidCapability) {
- if (appWidgetVisible || pendingTop || tempAllowlist) {
+ if (getUidVisibleAppWidget(uid) || mActivityManagerInternal.isPendingTopUid(uid)
+ || mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
return MODE_ALLOWED;
}
- switch (code) {
- case AppOpsManager.OP_FINE_LOCATION:
- case AppOpsManager.OP_COARSE_LOCATION:
- case AppOpsManager.OP_MONITOR_LOCATION:
- case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
- if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) == 0) {
- return MODE_IGNORED;
- } else {
- return MODE_ALLOWED;
- }
- case OP_CAMERA:
- if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) == 0) {
- return MODE_IGNORED;
- } else {
- return MODE_ALLOWED;
- }
- case OP_RECORD_AUDIO:
- case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
- if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) == 0) {
- return MODE_IGNORED;
- } else {
- return MODE_ALLOWED;
- }
+ int opCapability = getOpCapability(code);
+ if (opCapability != PROCESS_CAPABILITY_NONE) {
+ if ((uidCapability & opCapability) == 0) {
+ return MODE_IGNORED;
+ } else {
+ return MODE_ALLOWED;
+ }
}
if (uidState > AppOpsManager.resolveFirstUnrestrictedUidState(code)) {
@@ -187,6 +161,28 @@
return MODE_ALLOWED;
}
+ private int getOpCapability(int opCode) {
+ switch (opCode) {
+ case AppOpsManager.OP_FINE_LOCATION:
+ case AppOpsManager.OP_COARSE_LOCATION:
+ case AppOpsManager.OP_MONITOR_LOCATION:
+ case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
+ return PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+ case OP_CAMERA:
+ return PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+ case OP_RECORD_AUDIO:
+ case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
+ return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ default:
+ return PROCESS_CAPABILITY_NONE;
+ }
+ }
+
+ @Override
+ public boolean isUidInForeground(int uid) {
+ return evalMode(uid, OP_NONE, MODE_FOREGROUND) == MODE_ALLOWED;
+ }
+
@Override
public void addUidStateChangedCallback(Executor executor, UidStateChangedCallback callback) {
if (mUidStateChangedCallbacks.containsKey(callback)) {
diff --git a/services/core/java/com/android/server/appop/package-info.java b/services/core/java/com/android/server/appop/package-info.java
new file mode 100644
index 0000000..3b8fb9d
--- /dev/null
+++ b/services/core/java/com/android/server/appop/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @hide
+ * TODO(b/146466118) remove this javadoc tag
+ */
+@android.annotation.Hide
+package com.android.server.appop;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 92a9f46..4eb6c7f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1265,6 +1265,20 @@
0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
}
+ private void initVolumeStreamStates() {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ synchronized (VolumeStreamState.class) {
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+ int groupId = getVolumeGroupForStreamType(streamType);
+ if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
+ && sVolumeGroupStates.indexOfKey(groupId) >= 0) {
+ streamState.setVolumeGroupState(sVolumeGroupStates.get(groupId));
+ }
+ }
+ }
+ }
+
/**
* Separating notification volume from ring is NOT of aliasing the corresponding streams
* @param properties
@@ -1292,6 +1306,8 @@
initVolumeGroupStates();
mSoundDoseHelper.initSafeUsbMediaVolumeIndex();
+ // Link VGS on VSS
+ initVolumeStreamStates();
// Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode.
@@ -2610,13 +2626,11 @@
}
if (!TextUtils.isEmpty(packageName)) {
PackageManager pm = mContext.getPackageManager();
- ActivityManager am =
- (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE);
if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
== PackageManager.PERMISSION_GRANTED) {
try {
- assistantUid = pm.getPackageUidAsUser(packageName, am.getCurrentUser());
+ assistantUid = pm.getPackageUidAsUser(packageName, getCurrentUserId());
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG,
"updateAssistantUId() could not find UID for package: " + packageName);
@@ -3482,15 +3496,7 @@
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
- for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (streamTypeAlias == mStreamVolumeAlias[stream]) {
- if (!(readCameraSoundForced()
- && (mStreamStates[stream].getStreamType()
- == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
- mStreamStates[stream].mute(state);
- }
- }
- }
+ muteAliasStreams(streamTypeAlias, state);
} else if ((direction == AudioManager.ADJUST_RAISE)
&& mSoundDoseHelper.raiseVolumeDisplaySafeMediaVolume(streamTypeAlias,
aliasIndex + step, device, flags)) {
@@ -3505,7 +3511,7 @@
// Unmute the stream if it was previously muted
if (direction == AudioManager.ADJUST_RAISE) {
// unmute immediately for volume up
- streamState.mute(false);
+ muteAliasStreams(streamTypeAlias, false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
@@ -3631,6 +3637,42 @@
sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
}
+ /**
+ * Loops on aliasted stream, update the mute cache attribute of each
+ * {@see AudioService#VolumeStreamState}, and then apply the change.
+ * It prevents to unnecessary {@see AudioSystem#setStreamVolume} done for each stream
+ * and aliases before mute change changed and after.
+ */
+ private void muteAliasStreams(int streamAlias, boolean state) {
+ synchronized (VolumeStreamState.class) {
+ List<Integer> streamsToMute = new ArrayList<>();
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ if (streamAlias == mStreamVolumeAlias[stream]) {
+ if (!(readCameraSoundForced()
+ && (mStreamStates[stream].getStreamType()
+ == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
+ boolean changed = mStreamStates[stream].mute(state, /* apply= */ false);
+ if (changed) {
+ streamsToMute.add(stream);
+ }
+ }
+ }
+ }
+ streamsToMute.forEach(streamToMute -> {
+ mStreamStates[streamToMute].doMute();
+ broadcastMuteSetting(streamToMute, state);
+ });
+ }
+ }
+
+ private void broadcastMuteSetting(int streamType, boolean isMuted) {
+ // Stream mute changed, fire the intent.
+ Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
+ intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, isMuted);
+ sendBroadcastToAll(intent, null /* options */);
+ }
+
// Called after a delay when volume down is pressed while muted
private void onUnmuteStream(int stream, int flags) {
boolean wasMuted;
@@ -3730,7 +3772,8 @@
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO)
&& (getDeviceForStream(stream) == device)) {
- mStreamStates[stream].mute(index == 0);
+ // As adjustStreamVolume with muteAdjust flags mute/unmutes stream and aliased streams.
+ muteAliasStreams(stream, index == 0);
}
}
@@ -3774,23 +3817,23 @@
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */
- public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
+ @Override
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ /** @see AudioManager#setVolumeGroupVolumeIndex(int, int, int) */
+ public void setVolumeGroupVolumeIndex(int groupId, int index, int flags,
String callingPackage, String attributionTag) {
- super.setVolumeIndexForAttributes_enforcePermission();
-
- Objects.requireNonNull(attr, "attr must not be null");
- int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
- attr, /* fallbackOnDefault= */false);
- if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
- Log.e(TAG, ": no volume group found for attributes " + attr.toString());
+ super.setVolumeGroupVolumeIndex_enforcePermission();
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
return;
}
- VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
- sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(),
- index, flags, callingPackage + ", user " + ActivityManager.getCurrentUser()));
+ sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, vgs.name(),
+ index, flags, callingPackage + ", user " + getCurrentUserId()));
vgs.setVolumeIndex(index, flags);
@@ -3799,7 +3842,7 @@
try {
ensureValidStreamType(groupedStream);
} catch (IllegalArgumentException e) {
- Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream
+ Log.d(TAG, "volume group " + groupId + " has internal streams (" + groupedStream
+ "), do not change associated stream volume");
continue;
}
@@ -3821,39 +3864,55 @@
return null;
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- /** @see AudioManager#getVolumeIndexForAttributes(attr) */
- public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
- super.getVolumeIndexForAttributes_enforcePermission();
-
- Objects.requireNonNull(attr, "attr must not be null");
+ @Override
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ /** @see AudioManager#getVolumeGroupVolumeIndex(int) */
+ public int getVolumeGroupVolumeIndex(int groupId) {
+ super.getVolumeGroupVolumeIndex_enforcePermission();
synchronized (VolumeStreamState.class) {
- int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
- attr, /* fallbackOnDefault= */false);
- if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
- throw new IllegalArgumentException("No volume group for attributes " + attr);
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
}
- VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
- return vgs.isMuted() ? vgs.getMinIndex() : vgs.getVolumeIndex();
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ // Return 0 when muted, not min index since for e.g. Voice Call, it has a non zero
+ // min but it mutable on permission condition.
+ return vgs.isMuted() ? 0 : vgs.getVolumeIndex();
}
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */
- public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
- super.getMaxVolumeIndexForAttributes_enforcePermission();
-
- Objects.requireNonNull(attr, "attr must not be null");
- return AudioSystem.getMaxVolumeIndexForAttributes(attr);
+ /** @see AudioManager#getVolumeGroupMaxVolumeIndex(int) */
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public int getVolumeGroupMaxVolumeIndex(int groupId) {
+ super.getVolumeGroupMaxVolumeIndex_enforcePermission();
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getMaxIndex();
+ }
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- /** @see AudioManager#getMinVolumeIndexForAttributes(attr) */
- public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
- super.getMinVolumeIndexForAttributes_enforcePermission();
-
- Objects.requireNonNull(attr, "attr must not be null");
- return AudioSystem.getMinVolumeIndexForAttributes(attr);
+ /** @see AudioManager#getVolumeGroupMinVolumeIndex(int) */
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING
+ })
+ public int getVolumeGroupMinVolumeIndex(int groupId) {
+ super.getVolumeGroupMinVolumeIndex_enforcePermission();
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getMinIndex();
+ }
}
@Override
@@ -3922,6 +3981,71 @@
callingPackage, /*attributionTag*/ null);
}
+ /** @see AudioManager#adjustVolumeGroupVolume(int, int, int) */
+ public void adjustVolumeGroupVolume(int groupId, int direction, int flags,
+ String callingPackage) {
+ ensureValidDirection(direction);
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ // For compatibility reason, use stream API if group linked to a valid stream
+ boolean fallbackOnStream = false;
+ for (int stream : vgs.getLegacyStreamTypes()) {
+ try {
+ ensureValidStreamType(stream);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "volume group " + groupId + " has internal streams (" + stream
+ + "), do not change associated stream volume");
+ continue;
+ }
+ // Note: Group and Stream does not share same convention, 0 is mute for stream,
+ // min index is acting as mute for Groups
+ if (vgs.isVssMuteBijective(stream)) {
+ adjustStreamVolume(stream, direction, flags, callingPackage);
+ if (isMuteAdjust(direction)) {
+ // will be propagated to all aliased streams
+ return;
+ }
+ fallbackOnStream = true;
+ }
+ }
+ if (fallbackOnStream) {
+ // Handled by at least one stream, will be propagated to group, bailing out.
+ return;
+ }
+ sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_ADJUST_GROUP_VOL, vgs.name(),
+ direction, flags, callingPackage));
+ vgs.adjustVolume(direction, flags);
+ }
+
+ /** @see AudioManager#getLastAudibleVolumeGroupVolume(int) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.QUERY_AUDIO_STATE)
+ public int getLastAudibleVolumeGroupVolume(int groupId) {
+ super.getLastAudibleVolumeGroupVolume_enforcePermission();
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return 0;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getVolumeIndex();
+ }
+ }
+
+ /** @see AudioManager#isVolumeGroupMuted(int) */
+ public boolean isVolumeGroupMuted(int groupId) {
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return false;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.isMuted();
+ }
+ }
+
/** @see AudioManager#setStreamVolume(int, int, int)
* Part of service interface, check permissions here */
public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
@@ -5110,7 +5234,7 @@
}
private void setRingerMode(int ringerMode, String caller, boolean external) {
- if (mUseFixedVolume || mIsSingleVolume) {
+ if (mUseFixedVolume || mIsSingleVolume || mUseVolumeGroupAliases) {
return;
}
if (caller == null || caller.length() == 0) {
@@ -7006,20 +7130,21 @@
}
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
/**
* @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
* @param device the audio device to be affected
* @param deviceVolumeBehavior one of the device behaviors
*/
+ @android.annotation.EnforcePermission(anyOf =
+ {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
// verify permissions
- // verify arguments
super.setDeviceVolumeBehavior_enforcePermission();
-
+ // verify arguments
Objects.requireNonNull(device);
AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
+
sVolumeLogger.enqueue(new EventLogger.StringEvent("setDeviceVolumeBehavior: dev:"
+ AudioSystem.getOutputDeviceName(device.getInternalType()) + " addr:"
+ device.getAddress() + " behavior:"
@@ -7090,11 +7215,14 @@
* @param device the audio output device type
* @return the volume behavior for the device
*/
+ @android.annotation.EnforcePermission(anyOf =
+ {"MODIFY_AUDIO_ROUTING", "QUERY_AUDIO_STATE", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
public @AudioManager.DeviceVolumeBehavior
int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
- Objects.requireNonNull(device);
// verify permissions
- enforceQueryStateOrModifyRoutingPermission();
+ super.getDeviceVolumeBehavior_enforcePermission();
+ // verify parameters
+ Objects.requireNonNull(device);
return getDeviceVolumeBehaviorInt(device);
}
@@ -7413,6 +7541,16 @@
|| stream == AudioSystem.STREAM_BLUETOOTH_SCO;
}
+ private static int getVolumeGroupForStreamType(int stream) {
+ AudioAttributes attributes =
+ AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(stream);
+ if (attributes.equals(new AudioAttributes.Builder().build())) {
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+ return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
+ attributes, /* fallbackOnDefault= */ false);
+ }
+
// NOTE: Locking order for synchronized objects related to volume management:
// 1 mSettingsLock
// 2 VolumeStreamState.class
@@ -7521,14 +7659,62 @@
return mIsMuted;
}
+ public void adjustVolume(int direction, int flags) {
+ synchronized (AudioService.VolumeStreamState.class) {
+ int device = getDeviceForVolume();
+ int previousIndex = getIndex(device);
+ if (isMuteAdjust(direction) && !isMutable()) {
+ // Non mutable volume group
+ if (DEBUG_VOL) {
+ Log.d(TAG, "invalid mute on unmutable volume group " + name());
+ }
+ return;
+ }
+ switch (direction) {
+ case AudioManager.ADJUST_TOGGLE_MUTE: {
+ // Note: If muted by volume 0, unmute will restore volume 0.
+ mute(!mIsMuted);
+ break;
+ }
+ case AudioManager.ADJUST_UNMUTE:
+ // Note: If muted by volume 0, unmute will restore volume 0.
+ mute(false);
+ break;
+ case AudioManager.ADJUST_MUTE:
+ // May be already muted by setvolume 0, prevent from setting same value
+ if (previousIndex != 0) {
+ // bypass persist
+ mute(true);
+ }
+ mIsMuted = true;
+ break;
+ case AudioManager.ADJUST_RAISE:
+ // As for stream, RAISE during mute will increment the index
+ setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags);
+ break;
+ case AudioManager.ADJUST_LOWER:
+ // For stream, ADJUST_LOWER on a muted VSS is a no-op
+ // If we decide to unmute on ADJUST_LOWER, cannot fallback on
+ // adjustStreamVolume for group associated to legacy stream type
+ if (isMuted() && previousIndex != 0) {
+ mute(false);
+ } else {
+ int newIndex = Math.max(previousIndex - 1, mIndexMin);
+ setVolumeIndex(newIndex, device, flags);
+ }
+ break;
+ }
+ }
+ }
+
public int getVolumeIndex() {
- synchronized (VolumeStreamState.class) {
+ synchronized (AudioService.VolumeStreamState.class) {
return getIndex(getDeviceForVolume());
}
}
public void setVolumeIndex(int index, int flags) {
- synchronized (VolumeStreamState.class) {
+ synchronized (AudioService.VolumeStreamState.class) {
if (mUseFixedVolume) {
return;
}
@@ -7613,7 +7799,7 @@
public void applyAllVolumes(boolean userSwitch) {
String caller = "from vgs";
- synchronized (VolumeStreamState.class) {
+ synchronized (AudioService.VolumeStreamState.class) {
// apply device specific volumes first
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
@@ -7713,7 +7899,7 @@
Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
+ mAudioVolumeGroup.name()
+ ", device " + AudioSystem.getOutputDeviceName(device)
- + " and User=" + ActivityManager.getCurrentUser());
+ + " and User=" + getCurrentUserId());
}
boolean success = mSettings.putSystemIntForUser(mContentResolver,
getSettingNameForDevice(device),
@@ -7725,7 +7911,7 @@
}
public void readSettings() {
- synchronized (VolumeStreamState.class) {
+ synchronized (AudioService.VolumeStreamState.class) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -7752,7 +7938,7 @@
if (DEBUG_VOL) {
Log.v(TAG, "readSettings: found stored index " + getValidIndex(index)
+ " for group " + mAudioVolumeGroup.name() + ", device: " + name
- + ", User=" + ActivityManager.getCurrentUser());
+ + ", User=" + getCurrentUserId());
}
mIndexMap.put(device, getValidIndex(index));
}
@@ -7829,13 +8015,14 @@
// 4 VolumeStreamState.class
/*package*/ class VolumeStreamState {
private final int mStreamType;
+ private VolumeGroupState mVolumeGroupState = null;
private int mIndexMin;
// min index when user doesn't have permission to change audio settings
private int mIndexMinNoPerm;
private int mIndexMax;
- private boolean mIsMuted;
- private boolean mIsMutedInternally;
+ private boolean mIsMuted = false;
+ private boolean mIsMutedInternally = false;
private String mVolumeIndexSettingName;
@NonNull private Set<Integer> mObservedDeviceSet = new TreeSet<>();
@@ -7908,6 +8095,15 @@
}
/**
+ * Associate a {@link volumeGroupState} on the {@link VolumeStreamState}.
+ * <p> It helps to synchronize the index, mute attributes on the maching
+ * {@link volumeGroupState}
+ * @param volumeGroupState matching the {@link VolumeStreamState}
+ */
+ public void setVolumeGroupState(VolumeGroupState volumeGroupState) {
+ mVolumeGroupState = volumeGroupState;
+ }
+ /**
* Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission
* @param index minimum index expressed in "UI units", i.e. no 10x factor
*/
@@ -8168,6 +8364,9 @@
}
}
if (changed) {
+ // If associated to volume group, update group cache
+ updateVolumeGroupIndex(device, /* forceMuteState= */ false);
+
oldIndex = (oldIndex + 5) / 10;
index = (index + 5) / 10;
// log base stream changes to the event log
@@ -8285,6 +8484,28 @@
}
}
+ // If associated to volume group, update group cache
+ private void updateVolumeGroupIndex(int device, boolean forceMuteState) {
+ synchronized (VolumeStreamState.class) {
+ if (mVolumeGroupState != null) {
+ int groupIndex = (getIndex(device) + 5) / 10;
+ if (DEBUG_VOL) {
+ Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType
+ + ", muted=" + mIsMuted + ", device=" + device + ", index="
+ + getIndex(device) + ", group " + mVolumeGroupState.name()
+ + " Muted=" + mVolumeGroupState.isMuted() + ", Index=" + groupIndex
+ + ", forceMuteState=" + forceMuteState);
+ }
+ mVolumeGroupState.updateVolumeIndex(groupIndex, device);
+ // Only propage mute of stream when applicable
+ if (mIndexMin == 0 || isCallStream(mStreamType)) {
+ // For call stream, align mute only when muted, not when index is set to 0
+ mVolumeGroupState.mute(forceMuteState ? mIsMuted : groupIndex == 0);
+ }
+ }
+ }
+ }
+
/**
* Mute/unmute the stream
* @param state the new mute state
@@ -8293,27 +8514,10 @@
public boolean mute(boolean state) {
boolean changed = false;
synchronized (VolumeStreamState.class) {
- if (state != mIsMuted) {
- changed = true;
- mIsMuted = state;
-
- // Set the new mute volume. This propagates the values to
- // the audio system, otherwise the volume won't be changed
- // at the lower level.
- sendMsg(mAudioHandler,
- MSG_SET_ALL_VOLUMES,
- SENDMSG_QUEUE,
- 0,
- 0,
- this, 0);
- }
+ changed = mute(state, true);
}
if (changed) {
- // Stream mute changed, fire the intent.
- Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
- intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
- sendBroadcastToAll(intent, null /* options */);
+ broadcastMuteSetting(mStreamType, state);
}
return changed;
}
@@ -8345,6 +8549,44 @@
return mIsMuted || mIsMutedInternally;
}
+ /**
+ * Mute/unmute the stream
+ * @param state the new mute state
+ * @param apply true to propagate to HW, or false just to update the cache. May be needed
+ * to mute a stream and its aliases as applyAllVolume will force settings to aliases.
+ * It prevents unnecessary calls to {@see AudioSystem#setStreamVolume}
+ * @return true if the mute state was changed
+ */
+ public boolean mute(boolean state, boolean apply) {
+ synchronized (VolumeStreamState.class) {
+ boolean changed = state != mIsMuted;
+ if (changed) {
+ mIsMuted = state;
+ if (apply) {
+ doMute();
+ }
+ }
+ return changed;
+ }
+ }
+
+ public void doMute() {
+ synchronized (VolumeStreamState.class) {
+ // If associated to volume group, update group cache
+ updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */ true);
+
+ // Set the new mute volume. This propagates the values to
+ // the audio system, otherwise the volume won't be changed
+ // at the lower level.
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ this, 0);
+ }
+ }
+
public int getStreamType() {
return mStreamType;
}
@@ -8414,6 +8656,9 @@
pw.println();
pw.print(" Devices: ");
pw.print(AudioSystem.deviceSetToString(getDeviceSetForStream(mStreamType)));
+ pw.println();
+ pw.print(" Volume Group: ");
+ pw.println(mVolumeGroupState != null ? mVolumeGroupState.name() : "n/a");
}
}
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index d30bec7..58caf5a 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -17,7 +17,6 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -197,6 +196,7 @@
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
static final int VOL_SET_LE_AUDIO_VOL = 10;
+ static final int VOL_ADJUST_GROUP_VOL = 11;
final int mOp;
final int mStream;
@@ -204,7 +204,6 @@
final int mVal2;
final String mCaller;
final String mGroupName;
- final AudioAttributes mAudioAttributes;
/** used for VOL_ADJUST_VOL_UID,
* VOL_ADJUST_SUGG_VOL,
@@ -217,7 +216,6 @@
mVal2 = val2;
mCaller = caller;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -230,7 +228,6 @@
mStream = -1;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -243,7 +240,6 @@
mStream = -1;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -256,7 +252,6 @@
// unused
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -269,19 +264,18 @@
// unused
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
- /** used for VOL_SET_GROUP_VOL */
- VolumeEvent(int op, AudioAttributes aa, String group, int index, int flags, String caller) {
+ /** used for VOL_SET_GROUP_VOL,
+ * VOL_ADJUST_GROUP_VOL */
+ VolumeEvent(int op, String group, int index, int flags, String caller) {
mOp = op;
mStream = -1;
mVal1 = index;
mVal2 = flags;
mCaller = caller;
mGroupName = group;
- mAudioAttributes = aa;
logMetricEvent();
}
@@ -293,7 +287,6 @@
mVal2 = 0;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -335,6 +328,15 @@
.record();
return;
}
+ case VOL_ADJUST_GROUP_VOL:
+ new MediaMetrics.Item(mMetricsId)
+ .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
+ .set(MediaMetrics.Property.DIRECTION, mVal1 > 0 ? "up" : "down")
+ .set(MediaMetrics.Property.EVENT, "adjustVolumeGroupVolume")
+ .set(MediaMetrics.Property.FLAGS, mVal2)
+ .set(MediaMetrics.Property.GROUP, mGroupName)
+ .record();
+ return;
case VOL_SET_STREAM_VOL:
new MediaMetrics.Item(mMetricsId)
.set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
@@ -386,7 +388,6 @@
return;
case VOL_SET_GROUP_VOL:
new MediaMetrics.Item(mMetricsId)
- .set(MediaMetrics.Property.ATTRIBUTES, mAudioAttributes.toString())
.set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
.set(MediaMetrics.Property.EVENT, "setVolumeIndexForAttributes")
.set(MediaMetrics.Property.FLAGS, mVal2)
@@ -412,6 +413,13 @@
.append(" flags:0x").append(Integer.toHexString(mVal2))
.append(") from ").append(mCaller)
.toString();
+ case VOL_ADJUST_GROUP_VOL:
+ return new StringBuilder("adjustVolumeGroupVolume(group:")
+ .append(mGroupName)
+ .append(" dir:").append(AudioManager.adjustToString(mVal1))
+ .append(" flags:0x").append(Integer.toHexString(mVal2))
+ .append(") from ").append(mCaller)
+ .toString();
case VOL_ADJUST_STREAM_VOL:
return new StringBuilder("adjustStreamVolume(stream:")
.append(AudioSystem.streamToString(mStream))
@@ -460,8 +468,7 @@
.append(" stream:").append(AudioSystem.streamToString(mStream))
.toString();
case VOL_SET_GROUP_VOL:
- return new StringBuilder("setVolumeIndexForAttributes(attr:")
- .append(mAudioAttributes.toString())
+ return new StringBuilder("setVolumeIndexForAttributes(group:")
.append(" group: ").append(mGroupName)
.append(" index:").append(mVal1)
.append(" flags:0x").append(Integer.toHexString(mVal2))
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index b18be3c..08dcccf 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -86,7 +86,7 @@
private static final Set<String> sEligibleForMultiUser = Sets.newArraySet(
PERMISSION_HELPER, NOTIFICATION_HELPER, SYNC_SETTINGS_HELPER, APP_LOCALES_HELPER,
- ACCOUNT_MANAGER_HELPER);
+ ACCOUNT_MANAGER_HELPER, USAGE_STATS_HELPER);
private int mUserId = UserHandle.USER_SYSTEM;
@@ -100,7 +100,7 @@
addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(mUserId));
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
- addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(mUserId));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper(mUserId));
addHelper(SLICES_HELPER, new SliceBackupHelper(this));
diff --git a/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
index d6a70d3..4098c1a 100644
--- a/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
+++ b/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
@@ -1,9 +1,9 @@
package com.android.server.backup;
+import android.annotation.UserIdInt;
import android.app.backup.BlobBackupHelper;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.Context;
import android.os.UserHandle;
import android.util.Log;
@@ -26,8 +26,16 @@
// same as UsageStatsDatabase.KEY_USAGE_STATS
static final String KEY_USAGE_STATS = "usage_stats";
- public UsageStatsBackupHelper(Context context) {
+ private final @UserIdInt int mUserId;
+
+ /**
+ * Marshall/unmarshall the usagestats data for the given user
+ *
+ * @param userId The userId to backup/restore
+ */
+ public UsageStatsBackupHelper(@UserIdInt int userId) {
super(BLOB_VERSION, KEY_USAGE_STATS);
+ mUserId = userId;
}
@Override
@@ -38,8 +46,11 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
try {
+ // Note: Write 0 here deliberately so that a backup from a secondary user
+ // can still be restored to an older OS where the restore was always to user 0
+ // Writing the actual userId here would result in restores not working on pre-U.
out.writeInt(UserHandle.USER_SYSTEM);
- out.write(localUsageStatsManager.getBackupPayload(UserHandle.USER_SYSTEM, key));
+ out.write(localUsageStatsManager.getBackupPayload(mUserId, key));
} catch (IOException ioe) {
if (DEBUG) Log.e(TAG, "Failed to backup Usage Stats", ioe);
baos.reset();
@@ -49,7 +60,6 @@
return null;
}
-
@Override
protected void applyRestoredPayload(String key, byte[] payload) {
if (KEY_USAGE_STATS.equals(key)) {
@@ -57,10 +67,10 @@
LocalServices.getService(UsageStatsManagerInternal.class);
DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
try {
- int user = in.readInt();
+ in.readInt(); // Legacy userId parameter, read and ignore
byte[] restoreData = new byte[payload.length - 4];
in.read(restoreData, 0, restoreData.length);
- localUsageStatsManager.applyRestoredPayload(user, key, restoreData);
+ localUsageStatsManager.applyRestoredPayload(mUserId, key, restoreData);
} catch (IOException ioe) {
if (DEBUG) Log.e(TAG, "Failed to restore Usage Stats", ioe);
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 6f9a176..ecff0a7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -17,6 +17,10 @@
package com.android.server.clipboard;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_INVALID;
+import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
import android.Manifest;
import android.annotation.NonNull;
@@ -29,6 +33,8 @@
import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
import android.app.UriGrantsManager;
+import android.companion.virtual.VirtualDeviceManager;
+import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
@@ -39,11 +45,13 @@
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -64,10 +72,13 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
import android.util.SafetyProtectionUtils;
import android.util.Slog;
-import android.util.SparseArray;
+import android.util.SparseArrayMap;
import android.util.SparseBooleanArray;
+import android.view.Display;
import android.view.autofill.AutofillManagerInternal;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
@@ -130,7 +141,9 @@
private final IUriGrantsManager mUgm;
private final UriGrantsManagerInternal mUgmInternal;
private final WindowManagerInternal mWm;
- private final VirtualDeviceManagerInternal mVdm;
+ private final VirtualDeviceManagerInternal mVdmInternal;
+ private final VirtualDeviceManager mVdm;
+ private BroadcastReceiver mVirtualDeviceRemovedReceiver;
private final IUserManager mUm;
private final PackageManager mPm;
private final AppOpsManager mAppOps;
@@ -141,11 +154,15 @@
private final Handler mWorkerHandler;
@GuardedBy("mLock")
- private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
+ // Maps (userId, deviceId) to Clipboard.
+ private final SparseArrayMap<Integer, Clipboard> mClipboards = new SparseArrayMap<>();
@GuardedBy("mLock")
private boolean mShowAccessNotifications =
ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
+ @GuardedBy("mLock")
+ private boolean mAllowVirtualDeviceSilos =
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_ALLOW_VIRTUALDEVICE_SILOS;
@GuardedBy("mLock")
private int mMaxClassificationLength = DEFAULT_MAX_CLASSIFICATION_LENGTH;
@@ -163,7 +180,9 @@
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mWm = LocalServices.getService(WindowManagerInternal.class);
// Can be null; not all products have CDM + VirtualDeviceManager
- mVdm = LocalServices.getService(VirtualDeviceManagerInternal.class);
+ mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
+ mVdm = (mVdmInternal == null) ? null : getContext().getSystemService(
+ VirtualDeviceManager.class);
mPm = getContext().getPackageManager();
mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
@@ -174,7 +193,7 @@
if (IS_EMULATOR) {
mEmulatorClipboardMonitor = new EmulatorClipboardMonitor((clip) -> {
synchronized (mLock) {
- setPrimaryClipInternalLocked(getClipboardLocked(0), clip,
+ setPrimaryClipInternalLocked(getClipboardLocked(0, DEVICE_ID_DEFAULT), clip,
android.os.Process.SYSTEM_UID, null);
}
});
@@ -194,12 +213,39 @@
@Override
public void onStart() {
publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
+ if (mVdmInternal != null) {
+ registerVirtualDeviceRemovedListener();
+ }
+ }
+
+ private void registerVirtualDeviceRemovedListener() {
+ if (mVirtualDeviceRemovedReceiver != null) {
+ return;
+ }
+ mVirtualDeviceRemovedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(ACTION_VIRTUAL_DEVICE_REMOVED)) {
+ return;
+ }
+ final int removedDeviceId =
+ intent.getIntExtra(EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_INVALID);
+ synchronized (mLock) {
+ for (int i = mClipboards.numMaps() - 1; i >= 0; i--) {
+ mClipboards.delete(mClipboards.keyAt(i), removedDeviceId);
+ }
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter(ACTION_VIRTUAL_DEVICE_REMOVED);
+ getContext().registerReceiver(mVirtualDeviceRemovedReceiver, filter,
+ Context.RECEIVER_NOT_EXPORTED);
}
@Override
public void onUserStopped(@NonNull TargetUser user) {
synchronized (mLock) {
- mClipboards.remove(user.getUserIdentifier());
+ mClipboards.delete(user.getUserIdentifier());
}
}
@@ -209,6 +255,10 @@
DeviceConfig.NAMESPACE_CLIPBOARD,
ClipboardManager.DEVICE_CONFIG_SHOW_ACCESS_NOTIFICATIONS,
ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
+ mAllowVirtualDeviceSilos = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CLIPBOARD,
+ ClipboardManager.DEVICE_CONFIG_ALLOW_VIRTUALDEVICE_SILOS,
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_ALLOW_VIRTUALDEVICE_SILOS);
mMaxClassificationLength = DeviceConfig.getInt(DeviceConfig.NAMESPACE_CLIPBOARD,
PROPERTY_MAX_CLASSIFICATION_LENGTH, DEFAULT_MAX_CLASSIFICATION_LENGTH);
}
@@ -226,8 +276,9 @@
}
}
- private class PerUserClipboard {
- final int userId;
+ private static class Clipboard {
+ public final int userId;
+ public final int deviceId;
final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
= new RemoteCallbackList<IOnPrimaryClipChangedListener>();
@@ -254,8 +305,9 @@
/** The text classifier session that is used to annotate the text in the primary clip. */
TextClassifier mTextClassifier;
- PerUserClipboard(int userId) {
+ Clipboard(int userId, int deviceId) {
this.userId = userId;
+ this.deviceId = deviceId;
}
}
@@ -333,6 +385,54 @@
}
/**
+ * Determines which deviceId to use for selecting a Clipboard, depending on where a given app
+ * is running.
+ *
+ * @param requestedDeviceId the requested deviceId passed in from the client side
+ * @param uid the intended app uid
+ * @return a deviceId to use in selecting the appropriate clipboard, or
+ * DEVICE_ID_INVALID if this uid should not be allowed access. A value of DEVICE_ID_DEFAULT
+ * means just use the "regular" clipboard.
+ */
+ private int getIntendingDeviceId(int requestedDeviceId, int uid) {
+ if (mVdmInternal == null) {
+ return DEVICE_ID_DEFAULT;
+ }
+
+ ArraySet<Integer> virtualDeviceIds = mVdmInternal.getDeviceIdsForUid(uid);
+
+ synchronized (mLock) {
+ if (!mAllowVirtualDeviceSilos
+ && (!virtualDeviceIds.isEmpty() || requestedDeviceId != DEVICE_ID_DEFAULT)) {
+ return DEVICE_ID_INVALID;
+ }
+ }
+
+ if (requestedDeviceId != DEVICE_ID_DEFAULT) {
+ // Privileged apps that own the VirtualDevices, or regular apps running on it, can
+ // request it by id.
+ if (mVdmInternal.getDeviceOwnerUid(requestedDeviceId) == uid
+ || virtualDeviceIds.contains(requestedDeviceId)) {
+ return requestedDeviceId;
+ }
+ return DEVICE_ID_INVALID;
+ }
+
+ // The common case is apps running normally (not on a VirtualDevice).
+ if (virtualDeviceIds.isEmpty()) {
+ return DEVICE_ID_DEFAULT;
+ }
+
+ // If an app is running on more than one VirtualDevice, it isn't clear which clipboard they
+ // should use.
+ if (virtualDeviceIds.size() > 1) {
+ return DEVICE_ID_INVALID;
+ }
+
+ return virtualDeviceIds.valueAt(0);
+ }
+
+ /**
* To handle the difference between userId and intendingUserId, uid and intendingUid.
*
* userId means that comes from the calling side and should be validated by
@@ -364,8 +464,10 @@
ClipData clip,
String callingPackage,
String attributionTag,
- @UserIdInt int userId) {
- checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, callingPackage);
+ @UserIdInt int userId,
+ int deviceId) {
+ checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, deviceId,
+ callingPackage);
}
@Override
@@ -374,10 +476,12 @@
String callingPackage,
String attributionTag,
@UserIdInt int userId,
+ int deviceId,
String sourcePackage) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE,
"Requires SET_CLIP_SOURCE permission");
- checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, sourcePackage);
+ checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, deviceId,
+ sourcePackage);
}
private void checkAndSetPrimaryClip(
@@ -385,41 +489,46 @@
String callingPackage,
String attributionTag,
@UserIdInt int userId,
+ int deviceId,
String sourcePackage) {
if (clip == null || clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_WRITE_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
- intendingUserId)) {
+ intendingUserId,
+ intendingDeviceId)) {
return;
}
checkDataOwner(clip, intendingUid);
synchronized (mLock) {
- scheduleAutoClear(userId, intendingUid);
- setPrimaryClipInternalLocked(clip, intendingUid, sourcePackage);
+ scheduleAutoClear(userId, intendingUid, intendingDeviceId);
+ setPrimaryClipInternalLocked(clip, intendingUid, intendingDeviceId, sourcePackage);
}
}
- private void scheduleAutoClear(@UserIdInt int userId, int intendingUid) {
+ private void scheduleAutoClear(
+ @UserIdInt int userId, int intendingUid, int intendingDeviceId) {
final long oldIdentity = Binder.clearCallingIdentity();
try {
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
PROPERTY_AUTO_CLEAR_ENABLED, true)) {
+ Pair<Integer, Integer> userIdDeviceId = new Pair<>(userId, intendingDeviceId);
mClipboardClearHandler.removeEqualMessages(ClipboardClearHandler.MSG_CLEAR,
- userId);
+ userIdDeviceId);
Message clearMessage =
Message.obtain(
mClipboardClearHandler,
ClipboardClearHandler.MSG_CLEAR,
userId,
intendingUid,
- userId);
+ userIdDeviceId);
mClipboardClearHandler.sendMessageDelayed(clearMessage,
getTimeoutForAutoClear());
}
@@ -436,52 +545,57 @@
@Override
public void clearPrimaryClip(
- String callingPackage, String attributionTag, @UserIdInt int userId) {
+ String callingPackage, String attributionTag, @UserIdInt int userId, int deviceId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_WRITE_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
- intendingUserId)) {
+ intendingUserId,
+ intendingDeviceId)) {
return;
}
synchronized (mLock) {
mClipboardClearHandler.removeEqualMessages(ClipboardClearHandler.MSG_CLEAR,
- userId);
- setPrimaryClipInternalLocked(null, intendingUid, callingPackage);
+ new Pair<>(userId, deviceId));
+ setPrimaryClipInternalLocked(null, intendingUid, intendingDeviceId, callingPackage);
}
}
@Override
- public ClipData getPrimaryClip(String pkg, String attributionTag, @UserIdInt int userId) {
+ public ClipData getPrimaryClip(
+ String pkg, String attributionTag, @UserIdInt int userId, int deviceId) {
final int intendingUid = getIntendingUid(pkg, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_READ_CLIPBOARD,
pkg,
attributionTag,
intendingUid,
- intendingUserId)
+ intendingUserId,
+ intendingDeviceId)
|| isDeviceLocked(intendingUserId)) {
return null;
}
synchronized (mLock) {
try {
- addActiveOwnerLocked(intendingUid, pkg);
+ addActiveOwnerLocked(intendingUid, intendingDeviceId, pkg);
} catch (SecurityException e) {
// Permission could not be granted - URI may be invalid
Slog.i(TAG, "Could not grant permission to primary clip. Clearing clipboard.");
- setPrimaryClipInternalLocked(null, intendingUid, pkg);
+ setPrimaryClipInternalLocked(null, intendingUid, intendingDeviceId, pkg);
return null;
}
- PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
+ Clipboard clipboard = getClipboardLocked(intendingUserId, intendingDeviceId);
showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
notifyTextClassifierLocked(clipboard, pkg, intendingUid);
if (clipboard.primaryClip != null) {
- scheduleAutoClear(userId, intendingUid);
+ scheduleAutoClear(userId, intendingUid, intendingDeviceId);
}
return clipboard.primaryClip;
}
@@ -489,21 +603,23 @@
@Override
public ClipDescription getPrimaryClipDescription(
- String callingPackage, String attributionTag, @UserIdInt int userId) {
+ String callingPackage, String attributionTag, @UserIdInt int userId, int deviceId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_READ_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
intendingUserId,
+ intendingDeviceId,
false)
|| isDeviceLocked(intendingUserId)) {
return null;
}
synchronized (mLock) {
- PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
+ Clipboard clipboard = getClipboardLocked(intendingUserId, intendingDeviceId);
return clipboard.primaryClip != null
? clipboard.primaryClip.getDescription() : null;
}
@@ -511,21 +627,23 @@
@Override
public boolean hasPrimaryClip(
- String callingPackage, String attributionTag, @UserIdInt int userId) {
+ String callingPackage, String attributionTag, @UserIdInt int userId, int deviceId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_READ_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
intendingUserId,
+ intendingDeviceId,
false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
synchronized (mLock) {
- return getClipboardLocked(intendingUserId).primaryClip != null;
+ return getClipboardLocked(intendingUserId, intendingDeviceId).primaryClip != null;
}
}
@@ -534,11 +652,19 @@
IOnPrimaryClipChangedListener listener,
String callingPackage,
String attributionTag,
- @UserIdInt int userId) {
+ @UserIdInt int userId,
+ int deviceId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
+ if (intendingDeviceId == DEVICE_ID_INVALID) {
+ Slog.i(TAG, "addPrimaryClipChangedListener invalid deviceId for userId:"
+ + userId + " uid:" + intendingUid + " callingPackage:" + callingPackage
+ + " requestedDeviceId:" + deviceId);
+ return;
+ }
synchronized (mLock) {
- getClipboardLocked(intendingUserId)
+ getClipboardLocked(intendingUserId, intendingDeviceId)
.primaryClipListeners
.register(
listener,
@@ -551,29 +677,41 @@
IOnPrimaryClipChangedListener listener,
String callingPackage,
String attributionTag,
- @UserIdInt int userId) {
+ @UserIdInt int userId,
+ int deviceId) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = getIntendingUserId(callingPackage, userId);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
+ if (intendingDeviceId == DEVICE_ID_INVALID) {
+ Slog.i(TAG, "removePrimaryClipChangedListener invalid deviceId for userId:"
+ + userId + " uid:" + intendingUid + " callingPackage:" + callingPackage);
+ return;
+ }
synchronized (mLock) {
- getClipboardLocked(intendingUserId).primaryClipListeners.unregister(listener);
+ getClipboardLocked(intendingUserId,
+ intendingDeviceId).primaryClipListeners.unregister(listener);
}
}
@Override
- public boolean hasClipboardText(String callingPackage, String attributionTag, int userId) {
+ public boolean hasClipboardText(
+ String callingPackage, String attributionTag, int userId, int deviceId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_READ_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
intendingUserId,
+ intendingDeviceId,
false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
synchronized (mLock) {
- PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
+ Clipboard clipboard = getClipboardLocked(intendingUserId, intendingDeviceId);
if (clipboard.primaryClip != null) {
CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
return text != null && text.length() > 0;
@@ -584,23 +722,25 @@
@Override
public String getPrimaryClipSource(
- String callingPackage, String attributionTag, int userId) {
+ String callingPackage, String attributionTag, int userId, int deviceId) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE,
"Requires SET_CLIP_SOURCE permission");
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
+ final int intendingDeviceId = getIntendingDeviceId(deviceId, intendingUid);
if (!clipboardAccessAllowed(
AppOpsManager.OP_READ_CLIPBOARD,
callingPackage,
attributionTag,
intendingUid,
intendingUserId,
+ intendingDeviceId,
false)
|| isDeviceLocked(intendingUserId)) {
return null;
}
synchronized (mLock) {
- PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
+ Clipboard clipboard = getClipboardLocked(intendingUserId, intendingDeviceId);
if (clipboard.primaryClip != null) {
return clipboard.mPrimaryClipPackage;
}
@@ -621,11 +761,13 @@
case MSG_CLEAR:
final int userId = msg.arg1;
final int intendingUid = msg.arg2;
+ final int intendingDeviceId = ((Pair<Integer, Integer>) msg.obj).second;
synchronized (mLock) {
- if (getClipboardLocked(userId).primaryClip != null) {
+ if (getClipboardLocked(userId, intendingDeviceId).primaryClip != null) {
FrameworkStatsLog.write(FrameworkStatsLog.CLIPBOARD_CLEARED,
FrameworkStatsLog.CLIPBOARD_CLEARED__SOURCE__AUTO_CLEAR);
- setPrimaryClipInternalLocked(null, intendingUid, null);
+ setPrimaryClipInternalLocked(
+ null, intendingUid, intendingDeviceId, null);
}
}
break;
@@ -637,13 +779,13 @@
};
@GuardedBy("mLock")
- private PerUserClipboard getClipboardLocked(@UserIdInt int userId) {
- PerUserClipboard puc = mClipboards.get(userId);
- if (puc == null) {
- puc = new PerUserClipboard(userId);
- mClipboards.put(userId, puc);
+ private Clipboard getClipboardLocked(@UserIdInt int userId, int deviceId) {
+ Clipboard clipboard = mClipboards.get(userId, deviceId);
+ if (clipboard == null) {
+ clipboard = new Clipboard(userId, deviceId);
+ mClipboards.add(userId, deviceId, clipboard);
}
- return puc;
+ return clipboard;
}
List<UserInfo> getRelatedProfiles(@UserIdInt int userId) {
@@ -675,19 +817,20 @@
void setPrimaryClipInternal(@Nullable ClipData clip, int uid) {
synchronized (mLock) {
- setPrimaryClipInternalLocked(clip, uid, null);
+ setPrimaryClipInternalLocked(clip, uid, DEVICE_ID_DEFAULT, null);
}
}
@GuardedBy("mLock")
private void setPrimaryClipInternalLocked(
- @Nullable ClipData clip, int uid, @Nullable String sourcePackage) {
+ @Nullable ClipData clip, int uid, int deviceId, @Nullable String sourcePackage) {
mEmulatorClipboardMonitor.accept(clip);
final int userId = UserHandle.getUserId(uid);
// Update this user
- setPrimaryClipInternalLocked(getClipboardLocked(userId), clip, uid, sourcePackage);
+ setPrimaryClipInternalLocked(getClipboardLocked(userId, deviceId), clip, uid,
+ sourcePackage);
// Update related users
List<UserInfo> related = getRelatedProfiles(userId);
@@ -722,7 +865,7 @@
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
if (canCopyIntoProfile) {
setPrimaryClipInternalNoClassifyLocked(
- getClipboardLocked(id), clip, uid, sourcePackage);
+ getClipboardLocked(id, deviceId), clip, uid, sourcePackage);
}
}
}
@@ -730,7 +873,7 @@
}
}
- void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
+ void setPrimaryClipInternal(Clipboard clipboard, @Nullable ClipData clip,
int uid) {
synchronized (mLock) {
setPrimaryClipInternalLocked(clipboard, clip, uid, null);
@@ -738,18 +881,18 @@
}
@GuardedBy("mLock")
- private void setPrimaryClipInternalLocked(PerUserClipboard clipboard, @Nullable ClipData clip,
+ private void setPrimaryClipInternalLocked(Clipboard clipboard, @Nullable ClipData clip,
int uid, @Nullable String sourcePackage) {
final int userId = UserHandle.getUserId(uid);
if (clip != null) {
- startClassificationLocked(clip, userId);
+ startClassificationLocked(clip, userId, clipboard.deviceId);
}
setPrimaryClipInternalNoClassifyLocked(clipboard, clip, uid, sourcePackage);
}
@GuardedBy("mLock")
- private void setPrimaryClipInternalNoClassifyLocked(PerUserClipboard clipboard,
+ private void setPrimaryClipInternalNoClassifyLocked(Clipboard clipboard,
@Nullable ClipData clip, int uid, @Nullable String sourcePackage) {
revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
@@ -775,7 +918,7 @@
sendClipChangedBroadcast(clipboard);
}
- private void sendClipChangedBroadcast(PerUserClipboard clipboard) {
+ private void sendClipChangedBroadcast(Clipboard clipboard) {
final long ident = Binder.clearCallingIdentity();
final int n = clipboard.primaryClipListeners.beginBroadcast();
try {
@@ -789,7 +932,8 @@
li.mPackageName,
li.mAttributionTag,
li.mUid,
- UserHandle.getUserId(li.mUid))) {
+ UserHandle.getUserId(li.mUid),
+ clipboard.deviceId)) {
clipboard.primaryClipListeners.getBroadcastItem(i)
.dispatchPrimaryClipChanged();
}
@@ -805,7 +949,8 @@
}
@GuardedBy("mLock")
- private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId) {
+ private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId,
+ int deviceId) {
CharSequence text = (clip.getItemCount() == 0) ? null : clip.getItemAt(0).getText();
if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength) {
clip.getDescription().setClassificationStatus(
@@ -830,12 +975,13 @@
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
return;
}
- mWorkerHandler.post(() -> doClassification(text, clip, classifier, userId));
+ mWorkerHandler.post(() -> doClassification(text, clip, classifier, userId, deviceId));
}
@WorkerThread
private void doClassification(
- CharSequence text, ClipData clip, TextClassifier classifier, @UserIdInt int userId) {
+ CharSequence text, ClipData clip, TextClassifier classifier, @UserIdInt int userId,
+ int deviceId) {
TextLinks.Request request = new TextLinks.Request.Builder(text).build();
TextLinks links = classifier.generateLinks(request);
@@ -852,7 +998,7 @@
}
synchronized (mLock) {
- PerUserClipboard clipboard = getClipboardLocked(userId);
+ Clipboard clipboard = getClipboardLocked(userId, deviceId);
if (clipboard.primaryClip == clip) {
applyClassificationAndSendBroadcastLocked(
clipboard, confidences, links, classifier);
@@ -867,7 +1013,7 @@
final boolean canCopyIntoProfile = !hasRestriction(
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
if (canCopyIntoProfile) {
- PerUserClipboard relatedClipboard = getClipboardLocked(id);
+ Clipboard relatedClipboard = getClipboardLocked(id, deviceId);
if (hasTextLocked(relatedClipboard, text)) {
applyClassificationAndSendBroadcastLocked(
relatedClipboard, confidences, links, classifier);
@@ -882,7 +1028,7 @@
@GuardedBy("mLock")
private void applyClassificationAndSendBroadcastLocked(
- PerUserClipboard clipboard, ArrayMap<String, Float> confidences, TextLinks links,
+ Clipboard clipboard, ArrayMap<String, Float> confidences, TextLinks links,
TextClassifier classifier) {
clipboard.mTextClassifier = classifier;
clipboard.primaryClip.getDescription().setConfidenceScores(confidences);
@@ -893,7 +1039,7 @@
}
@GuardedBy("mLock")
- private boolean hasTextLocked(PerUserClipboard clipboard, @NonNull CharSequence text) {
+ private boolean hasTextLocked(Clipboard clipboard, @NonNull CharSequence text) {
return clipboard.primaryClip != null
&& clipboard.primaryClip.getItemCount() > 0
&& text.equals(clipboard.primaryClip.getItemAt(0).getText());
@@ -972,7 +1118,7 @@
}
@GuardedBy("mLock")
- private void addActiveOwnerLocked(int uid, String pkg) {
+ private void addActiveOwnerLocked(int uid, int deviceId, String pkg) {
final IPackageManager pm = AppGlobals.getPackageManager();
final int targetUserHandle = UserHandle.getCallingUserId();
final long oldIdentity = Binder.clearCallingIdentity();
@@ -990,7 +1136,7 @@
} finally {
Binder.restoreCallingIdentity(oldIdentity);
}
- PerUserClipboard clipboard = getClipboardLocked(UserHandle.getUserId(uid));
+ Clipboard clipboard = getClipboardLocked(UserHandle.getUserId(uid), deviceId);
if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
@@ -1025,7 +1171,7 @@
}
}
- private void revokeUris(PerUserClipboard clipboard) {
+ private void revokeUris(Clipboard clipboard) {
if (clipboard.primaryClip == null) {
return;
}
@@ -1036,8 +1182,14 @@
}
private boolean clipboardAccessAllowed(
- int op, String callingPackage, String attributionTag, int uid, @UserIdInt int userId) {
- return clipboardAccessAllowed(op, callingPackage, attributionTag, uid, userId, true);
+ int op,
+ String callingPackage,
+ String attributionTag,
+ int uid,
+ @UserIdInt int userId,
+ int intendingDeviceId) {
+ return clipboardAccessAllowed(op, callingPackage, attributionTag, uid, userId,
+ intendingDeviceId, true);
}
private boolean clipboardAccessAllowed(
@@ -1046,6 +1198,7 @@
String attributionTag,
int uid,
@UserIdInt int userId,
+ int intendingDeviceId,
boolean shouldNoteOp) {
boolean allowed;
@@ -1053,10 +1206,9 @@
// First, verify package ownership to ensure use below is safe.
mAppOps.checkPackage(uid, callingPackage);
- // Nothing in a virtual session is permitted to touch clipboard contents
- if (mVdm != null && mVdm.isAppRunningOnAnyVirtualDevice(uid)) {
+ if (intendingDeviceId == DEVICE_ID_INVALID) {
Slog.w(TAG, "Clipboard access denied to " + uid + "/" + callingPackage
- + " within a virtual device session");
+ + " due to invalid device id");
return false;
}
@@ -1077,7 +1229,8 @@
// Binder.getCallingUid(). Without checking, the user X can't copy any thing from
// INTERNAL_SYSTEM_WINDOW to the other applications.
if (!allowed) {
- allowed = mWm.isUidFocused(uid)
+ allowed = isDefaultDeviceAndUidFocused(intendingDeviceId, uid)
+ || isVirtualDeviceAndUidFocused(intendingDeviceId, uid)
|| isInternalSysWindowAppWithWindowFocus(callingPackage);
}
if (!allowed && mContentCaptureInternal != null) {
@@ -1098,6 +1251,12 @@
// userId must pass intending userId. i.e. user#10.
allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId);
}
+ if (!allowed && intendingDeviceId != DEVICE_ID_DEFAULT) {
+ // Privileged apps which own a VirtualDevice are allowed to read its clipboard
+ // in the background.
+ allowed = (mVdmInternal != null)
+ && mVdmInternal.getDeviceOwnerUid(intendingDeviceId) == uid;
+ }
break;
case AppOpsManager.OP_WRITE_CLIPBOARD:
// Writing is allowed without focus.
@@ -1123,6 +1282,19 @@
return appOpsResult == AppOpsManager.MODE_ALLOWED;
}
+ private boolean isDefaultDeviceAndUidFocused(int intendingDeviceId, int uid) {
+ return intendingDeviceId == DEVICE_ID_DEFAULT && mWm.isUidFocused(uid);
+ }
+
+ private boolean isVirtualDeviceAndUidFocused(int intendingDeviceId, int uid) {
+ if (intendingDeviceId == DEVICE_ID_DEFAULT || mVdm == null) {
+ return false;
+ }
+ int topFocusedDisplayId = mWm.getTopFocusedDisplayId();
+ int focusedDeviceId = mVdm.getDeviceIdForDisplayId(topFocusedDisplayId);
+ return (focusedDeviceId == intendingDeviceId) && mWm.isUidFocused(uid);
+ }
+
private boolean isDefaultIme(int userId, String packageName) {
String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, userId);
@@ -1141,7 +1313,7 @@
*/
@GuardedBy("mLock")
private void showAccessNotificationLocked(String callingPackage, int uid, @UserIdInt int userId,
- PerUserClipboard clipboard) {
+ Clipboard clipboard) {
if (clipboard.primaryClip == null) {
return;
}
@@ -1174,8 +1346,8 @@
if (clipboard.mNotifiedUids.get(uid)) {
return;
}
- clipboard.mNotifiedUids.put(uid, true);
+ final ArraySet<Context> toastContexts = getToastContexts(clipboard);
Binder.withCleanCallingIdentity(() -> {
try {
CharSequence callingAppLabel = mPm.getApplicationLabel(
@@ -1183,23 +1355,72 @@
String message =
getContext().getString(R.string.pasted_from_clipboard, callingAppLabel);
Slog.i(TAG, message);
- Toast toastToShow;
- if (SafetyProtectionUtils.shouldShowSafetyProtectionResources(getContext())) {
- Drawable safetyProtectionIcon = getContext()
- .getDrawable(R.drawable.ic_safety_protection);
- toastToShow = Toast.makeCustomToastWithIcon(getContext(),
- UiThread.get().getLooper(), message,
- Toast.LENGTH_SHORT, safetyProtectionIcon);
- } else {
- toastToShow = Toast.makeText(
- getContext(), UiThread.get().getLooper(), message,
- Toast.LENGTH_SHORT);
+ for (int i = 0; i < toastContexts.size(); i++) {
+ Context toastContext = toastContexts.valueAt(i);
+ Toast toastToShow;
+ if (SafetyProtectionUtils.shouldShowSafetyProtectionResources(getContext())) {
+ Drawable safetyProtectionIcon = getContext()
+ .getDrawable(R.drawable.ic_safety_protection);
+ toastToShow = Toast.makeCustomToastWithIcon(toastContext,
+ UiThread.get().getLooper(), message,
+ Toast.LENGTH_SHORT, safetyProtectionIcon);
+ } else {
+ toastToShow = Toast.makeText(
+ toastContext, UiThread.get().getLooper(), message,
+ Toast.LENGTH_SHORT);
+ }
+ toastToShow.show();
}
- toastToShow.show();
} catch (PackageManager.NameNotFoundException e) {
// do nothing
}
});
+
+ clipboard.mNotifiedUids.put(uid, true);
+ }
+
+ /**
+ * Returns the context(s) to use for toasts related to this clipboard. Normally this will just
+ * contain a single context referencing the default display.
+ *
+ * If the clipboard is for a VirtualDevice, we attempt to return the single DisplayContext for
+ * the focused VirtualDisplay for that device, but might need to return the contexts for
+ * multiple displays if the VirtualDevice has several but none of them were focused.
+ */
+ private ArraySet<Context> getToastContexts(Clipboard clipboard) throws IllegalStateException {
+ ArraySet<Context> contexts = new ArraySet<>();
+
+ if (clipboard.deviceId != DEVICE_ID_DEFAULT) {
+ DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
+
+ int topFocusedDisplayId = mWm.getTopFocusedDisplayId();
+ ArraySet<Integer> displayIds = mVdmInternal.getDisplayIdsForDevice(clipboard.deviceId);
+
+ if (displayIds.contains(topFocusedDisplayId)) {
+ Display display = displayManager.getDisplay(topFocusedDisplayId);
+ if (display != null) {
+ contexts.add(getContext().createDisplayContext(display));
+ return contexts;
+ }
+ }
+
+ for (int i = 0; i < displayIds.size(); i++) {
+ Display display = displayManager.getDisplay(displayIds.valueAt(i));
+ if (display != null) {
+ contexts.add(getContext().createDisplayContext(display));
+ }
+ }
+ if (!contexts.isEmpty()) {
+ return contexts;
+ }
+ Slog.e(TAG, "getToastContexts Couldn't find any VirtualDisplays for VirtualDevice "
+ + clipboard.deviceId);
+ // Since we couldn't find any VirtualDisplays to use at all, just fall through to using
+ // the default display below.
+ }
+
+ contexts.add(getContext());
+ return contexts;
}
/**
@@ -1221,7 +1442,7 @@
/** Potentially notifies the text classifier that an app is accessing a text clip. */
@GuardedBy("mLock")
private void notifyTextClassifierLocked(
- PerUserClipboard clipboard, String callingPackage, int callingUid) {
+ Clipboard clipboard, String callingPackage, int callingUid) {
if (clipboard.primaryClip == null) {
return;
}
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 974c04b..001cb10 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.companion.virtual.IVirtualDevice;
import android.os.LocaleList;
+import android.util.ArraySet;
import java.util.Set;
@@ -84,7 +85,7 @@
* *Note* this only checks VirtualDevices, and does not include information about whether
* the app is running on the default device or not.
*/
- public abstract @NonNull Set<Integer> getDeviceIdsForUid(int uid);
+ public abstract @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid);
/**
* Notifies that a virtual display is created.
@@ -132,4 +133,12 @@
* Returns true if the {@code displayId} is owned by any virtual device
*/
public abstract boolean isDisplayOwnedByAnyVirtualDevice(int displayId);
+
+ /**
+ * Gets the ids of VirtualDisplays owned by a VirtualDevice.
+ *
+ * @param deviceId which device we're asking about
+ * @return the set of display ids for all VirtualDisplays owned by the device
+ */
+ public abstract @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId);
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 4f00835..10abfdd 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1127,6 +1127,14 @@
}
}
+ public float convertToFloatScale(float nits) {
+ if (mCurrentBrightnessMapper != null) {
+ return mCurrentBrightnessMapper.convertToFloatScale(nits);
+ } else {
+ return -1.0f;
+ }
+ }
+
public void recalculateSplines(boolean applyAdjustment, float[] adjustment) {
mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 3fc50c4..d7c1529 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -322,6 +322,13 @@
public abstract float convertToNits(float brightness);
/**
+ * Converts the provided nits value to a float value if possible.
+ *
+ * Returns -1.0f if there's no available mapping for the nits to float.
+ */
+ public abstract float convertToFloatScale(float nits);
+
+ /**
* Adds a user interaction data point to the brightness mapping.
*
* This data point <b>must</b> exist on the brightness curve as a result of this call. This is
@@ -671,6 +678,11 @@
}
@Override
+ public float convertToFloatScale(float nits) {
+ return -1.0f;
+ }
+
+ @Override
public void addUserDataPoint(float lux, float brightness) {
float unadjustedBrightness = getUnadjustedBrightness(lux);
if (mLoggingEnabled) {
@@ -913,6 +925,11 @@
}
@Override
+ public float convertToFloatScale(float nits) {
+ return mNitsToBrightnessSpline.interpolate(nits);
+ }
+
+ @Override
public void addUserDataPoint(float lux, float brightness) {
float unadjustedBrightness = getUnadjustedBrightness(lux);
if (mLoggingEnabled) {
diff --git a/services/core/java/com/android/server/display/BrightnessSetting.java b/services/core/java/com/android/server/display/BrightnessSetting.java
index 7448611..4a9b562 100644
--- a/services/core/java/com/android/server/display/BrightnessSetting.java
+++ b/services/core/java/com/android/server/display/BrightnessSetting.java
@@ -96,7 +96,11 @@
mListeners.remove(l);
}
- void setBrightness(float brightness) {
+ /**
+ * Sets the brigtness and broadcasts the change to the listeners.
+ * @param brightness The value to which the brightness is to be set.
+ */
+ public void setBrightness(float brightness) {
if (Float.isNaN(brightness)) {
Slog.w(TAG, "Attempting to set invalid brightness");
return;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d558e69..c1d8cf4 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -109,6 +109,7 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IntArray;
@@ -260,6 +261,13 @@
final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>>
mDisplayWindowPolicyControllers = new SparseArray<>();
+ /**
+ * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
+ * {@link DisplayDevice#mUniqueId}.
+ */
+ public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
+ new ArrayMap<>();
+
// List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
@@ -1640,7 +1648,19 @@
DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.onDisplayChanged();
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
+ + display.getDisplayIdLocked());
+ return;
+ }
+
+ // TODO (b/265793751): Set this DPC as a follower of the default DPC if needed,
+ // clear this DPC's followers if it's not a lead display
+
+ final String uniqueId = device.getUniqueId();
+ HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
+ dpc.onDisplayChanged(hbmMetadata);
}
}
@@ -1698,7 +1718,15 @@
final int displayId = display.getDisplayIdLocked();
final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.onDisplayChanged();
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
+ + display.getDisplayIdLocked());
+ return;
+ }
+ final String uniqueId = device.getUniqueId();
+ HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
+ dpc.onDisplayChanged(hbmMetadata);
}
}
@@ -2651,6 +2679,26 @@
mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
}
+ private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
+ + display.getDisplayIdLocked());
+ return null;
+ }
+
+ final String uniqueId = device.getUniqueId();
+
+ if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
+ return mHighBrightnessModeMetadataMap.get(uniqueId);
+ }
+
+ // HBM Time info not present. Create a new one for this physical display.
+ HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
+ mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
+ return hbmInfo;
+ }
+
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
private void addDisplayPowerControllerLocked(LogicalDisplay display) {
if (mPowerHandler == null) {
@@ -2666,17 +2714,23 @@
display, mSyncRoot);
final DisplayPowerControllerInterface displayPowerController;
+ // If display is internal and has a HighBrightnessModeMetadata mapping, use that.
+ // Or create a new one and use that.
+ // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to
+ // displayPowerController, so the hbm info can be correctly associated
+ // with the corresponding displaydevice.
+ HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display);
if (DeviceConfig.getBoolean("display_manager",
"use_newly_structured_display_power_controller", true)) {
displayPowerController = new DisplayPowerController2(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display));
+ () -> handleBrightnessChange(display), hbmMetadata);
} else {
displayPowerController = new DisplayPowerController(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display));
+ () -> handleBrightnessChange(display), hbmMetadata);
}
mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c960416..f8d6c5f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -3081,10 +3081,10 @@
@Override
public boolean supportsFrameRateOverride() {
- return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true)
+ return SurfaceFlingerProperties.enable_frame_rate_override().orElse(false)
&& !SurfaceFlingerProperties.frame_rate_override_for_native_rates()
- .orElse(false)
- && SurfaceFlingerProperties.frame_rate_override_global().orElse(true);
+ .orElse(true)
+ && SurfaceFlingerProperties.frame_rate_override_global().orElse(false);
}
private DisplayManager getDisplayManager() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index cdaa3d0..263c4d7 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -54,6 +54,7 @@
import android.util.MutableFloat;
import android.util.MutableInt;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.Display;
@@ -388,6 +389,7 @@
private float[] mNitsRange;
private final HighBrightnessModeController mHbmController;
+ private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
private final BrightnessThrottler mBrightnessThrottler;
@@ -449,6 +451,10 @@
// PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set.
private float mTemporaryScreenBrightness;
+ // This brightness value is set in concurrent displays mode. It is the brightness value
+ // of the lead display that this DPC should follow.
+ private float mBrightnessToFollow;
+
// The last auto brightness adjustment that was set by the user and not temporary. Set to
// Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
private float mAutoBrightnessAdjustment;
@@ -498,6 +504,12 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+ // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
+ // is one lead display, the additional displays follow the brightness value of the lead display.
+ @GuardedBy("mLock")
+ private SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers =
+ new SparseArray();
+
/**
* Creates the display power controller.
*/
@@ -505,13 +517,14 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked();
mTag = "DisplayPowerController[" + mDisplayId + "]";
+ mHighBrightnessModeMetadata = hbmMetadata;
mSuspendBlockerIdUnfinishedBusiness = getSuspendBlockerUnfinishedBusinessId(mDisplayId);
mSuspendBlockerIdOnStateChanged = getSuspendBlockerOnStateChangedId(mDisplayId);
mSuspendBlockerIdProxPositive = getSuspendBlockerProxPositiveId(mDisplayId);
@@ -633,6 +646,7 @@
loadProximitySensor();
mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
+ mBrightnessToFollow = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -699,6 +713,48 @@
}
}
+ @Override
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ @Override
+ public void setBrightnessToFollow(float leadDisplayBrightness, float nits) {
+ if (mAutomaticBrightnessController == null || nits < 0) {
+ mBrightnessToFollow = leadDisplayBrightness;
+ } else {
+ float brightness = mAutomaticBrightnessController.convertToFloatScale(nits);
+ if (isValidBrightnessValue(brightness)) {
+ mBrightnessToFollow = brightness;
+ } else {
+ // The device does not support nits
+ mBrightnessToFollow = leadDisplayBrightness;
+ }
+ }
+ sendUpdatePowerState();
+ }
+
+ @Override
+ public void addDisplayBrightnessFollower(DisplayPowerControllerInterface follower) {
+ synchronized (mLock) {
+ mDisplayBrightnessFollowers.append(follower.getDisplayId(), follower);
+ }
+ sendUpdatePowerState();
+ }
+
+ @Override
+ public void clearDisplayBrightnessFollowers() {
+ SparseArray<DisplayPowerControllerInterface> followers;
+ synchronized (mLock) {
+ followers = mDisplayBrightnessFollowers.clone();
+ mDisplayBrightnessFollowers.clear();
+ }
+ for (int i = 0; i < followers.size(); i++) {
+ DisplayPowerControllerInterface follower = followers.valueAt(i);
+ follower.setBrightnessToFollow(PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1);
+ }
+ }
+
@Nullable
@Override
public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(
@@ -790,7 +846,7 @@
* Make sure DisplayManagerService.mSyncRoot is held when this is called
*/
@Override
- public void onDisplayChanged() {
+ public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
if (device == null) {
Slog.wtf(mTag, "Display Device is null in DisplayPowerController for display: "
@@ -812,7 +868,7 @@
mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config;
- loadFromDisplayDeviceConfig(token, info);
+ loadFromDisplayDeviceConfig(token, info, hbmMetadata);
/// Since the underlying display-device changed, we really don't know the
// last command that was sent to change it's state. Lets assume it is unknown so
@@ -864,7 +920,8 @@
}
}
- private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) {
+ private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info,
+ HighBrightnessModeMetadata hbmMetadata) {
// All properties that depend on the associated DisplayDevice and the DDC must be
// updated here.
loadBrightnessRampRates();
@@ -877,6 +934,7 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@@ -1237,6 +1295,7 @@
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
mTempBrightnessEvent.reset();
+ SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers;
synchronized (mLock) {
if (mStopped) {
return;
@@ -1265,6 +1324,8 @@
}
mustNotify = !mDisplayReadyLocked;
+
+ displayBrightnessFollowers = mDisplayBrightnessFollowers.clone();
}
// Compute the basic display state using the policy.
@@ -1372,6 +1433,11 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
}
+ if (Float.isNaN(brightnessState) && isValidBrightnessValue(mBrightnessToFollow)) {
+ brightnessState = mBrightnessToFollow;
+ mBrightnessReasonTemp.setReason(BrightnessReason.REASON_FOLLOWER);
+ }
+
if ((Float.isNaN(brightnessState))
&& isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) {
brightnessState = mPowerRequest.screenBrightnessOverride;
@@ -1553,6 +1619,11 @@
mAppliedThrottling = false;
}
+ for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
+ DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
+ follower.setBrightnessToFollow(brightnessState, convertToNits(brightnessState));
+ }
+
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -1961,7 +2032,7 @@
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.update();
}
- }, mContext);
+ }, mHighBrightnessModeMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
@@ -2664,6 +2735,7 @@
pw.println(" mPendingScreenBrightnessSetting="
+ mPendingScreenBrightnessSetting);
pw.println(" mTemporaryScreenBrightness=" + mTemporaryScreenBrightness);
+ pw.println(" mBrightnessToFollow=" + mBrightnessToFollow);
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mBrightnessReason=" + mBrightnessReason);
pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index da59cca..0cc4e93 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -52,6 +52,7 @@
import android.util.MutableFloat;
import android.util.MutableInt;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import com.android.internal.R;
@@ -68,6 +69,7 @@
import com.android.server.display.RampAnimator.DualRampAnimator;
import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
import com.android.server.display.brightness.DisplayBrightnessController;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
@@ -197,8 +199,6 @@
// mScreenBrightnessDimConfig.
private final float mScreenBrightnessMinimumDimAmount;
- private final float mScreenBrightnessDefault;
-
// True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
@@ -328,11 +328,10 @@
private float[] mNitsRange;
private final HighBrightnessModeController mHbmController;
+ private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
private final BrightnessThrottler mBrightnessThrottler;
- private final BrightnessSetting mBrightnessSetting;
-
private final Runnable mOnBrightnessChangeRunnable;
private final BrightnessEvent mLastBrightnessEvent;
@@ -383,19 +382,6 @@
@Nullable
private BrightnessConfiguration mBrightnessConfiguration;
- // The last brightness that was set by the user and not temporary. Set to
- // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded.
- private float mLastUserSetScreenBrightness = Float.NaN;
-
- // The screen brightness setting has changed but not taken effect yet. If this is different
- // from the current screen brightness setting then this is coming from something other than us
- // and should be considered a user interaction.
- private float mPendingScreenBrightnessSetting;
-
- // The last observed screen brightness setting, either set by us or by the settings app on
- // behalf of the user.
- private float mCurrentScreenBrightnessSetting;
-
// The last auto brightness adjustment that was set by the user and not temporary. Set to
// Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
private float mAutoBrightnessAdjustment;
@@ -416,7 +402,6 @@
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
private DualRampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
- private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener;
// True if this DisplayPowerController2 has been stopped and should no longer be running.
private boolean mStopped;
@@ -425,6 +410,13 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+
+ // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
+ // is one lead display, the additional displays follow the brightness value of the lead display.
+ @GuardedBy("mLock")
+ private SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers =
+ new SparseArray();
+
/**
* Creates the display power controller.
*/
@@ -432,7 +424,7 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
@@ -448,6 +440,7 @@
mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
() -> updatePowerState(), mDisplayId, mSensorManager);
+ mHighBrightnessModeMetadata = hbmMetadata;
mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController);
mTag = "DisplayPowerController2[" + mDisplayId + "]";
@@ -469,8 +462,6 @@
mBlanker = blanker;
mContext = context;
mBrightnessTracker = brightnessTracker;
- // TODO: b/186428377 update brightness setting when display changes
- mBrightnessSetting = brightnessSetting;
mOnBrightnessChangeRunnable = onBrightnessChangeRunnable;
PowerManager pm = context.getSystemService(PowerManager.class);
@@ -478,18 +469,13 @@
final Resources resources = context.getResources();
// DOZE AND DIM SETTINGS
- mScreenBrightnessDozeConfig = clampAbsoluteBrightness(
+ mScreenBrightnessDozeConfig = BrightnessUtils.clampAbsoluteBrightness(
pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE));
- mScreenBrightnessDimConfig = clampAbsoluteBrightness(
+ mScreenBrightnessDimConfig = BrightnessUtils.clampAbsoluteBrightness(
pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DIM));
mScreenBrightnessMinimumDimAmount = resources.getFloat(
R.dimen.config_screenBrightnessMinimumDimAmountFloat);
-
- // NORMAL SCREEN SETTINGS
- mScreenBrightnessDefault = clampAbsoluteBrightness(
- mLogicalDisplay.getDisplayInfoLocked().brightnessDefault);
-
loadBrightnessRampRates();
mSkipScreenOnBrightnessRamp = resources.getBoolean(
R.bool.config_skipScreenOnBrightnessRamp);
@@ -497,7 +483,10 @@
mHbmController = createHbmControllerLocked();
mBrightnessThrottler = createBrightnessThrottlerLocked();
-
+ mDisplayBrightnessController =
+ new DisplayBrightnessController(context, null,
+ mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault,
+ brightnessSetting, () -> postBrightnessChangeRunnable());
// Seed the cached brightness
saveBrightnessInfo(getScreenBrightnessSetting());
@@ -552,12 +541,7 @@
mBrightnessBucketsInDozeConfig = resources.getBoolean(
R.bool.config_displayBrightnessBucketsInDoze);
-
- mDisplayBrightnessController =
- new DisplayBrightnessController(context, null, mDisplayId);
- mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
- mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -707,7 +691,7 @@
* Make sure DisplayManagerService.mSyncRoot lock is held when this is called
*/
@Override
- public void onDisplayChanged() {
+ public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
if (device == null) {
Slog.wtf(mTag, "Display Device is null in DisplayPowerController2 for display: "
@@ -721,6 +705,7 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
+
mHandler.post(() -> {
boolean changed = false;
if (mDisplayDevice != device) {
@@ -729,7 +714,7 @@
mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config;
- loadFromDisplayDeviceConfig(token, info);
+ loadFromDisplayDeviceConfig(token, info, hbmMetadata);
mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config);
// Since the underlying display-device changed, we really don't know the
@@ -770,15 +755,14 @@
mAutomaticBrightnessController.stop();
}
- if (mBrightnessSetting != null) {
- mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
- }
+ mDisplayBrightnessController.stop();
mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
}
}
- private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) {
+ private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info,
+ HighBrightnessModeMetadata hbmMetadata) {
// All properties that depend on the associated DisplayDevice and the DDC must be
// updated here.
loadBrightnessRampRates();
@@ -790,6 +774,7 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@@ -849,12 +834,14 @@
if (mBrightnessTracker != null && brightness >= PowerManager.BRIGHTNESS_MIN) {
mBrightnessTracker.start(brightness);
}
- mBrightnessSettingListener = brightnessValue -> {
+
+ BrightnessSetting.BrightnessSettingListener brightnessSettingListener = brightnessValue -> {
Message msg = mHandler.obtainMessage(MSG_UPDATE_BRIGHTNESS, brightnessValue);
mHandler.sendMessage(msg);
};
+ mDisplayBrightnessController
+ .registerBrightnessSettingChangeListener(brightnessSettingListener);
- mBrightnessSetting.registerListener(mBrightnessSettingListener);
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
@@ -1131,6 +1118,7 @@
boolean mustInitialize = false;
int brightnessAdjustmentFlags = 0;
mTempBrightnessEvent.reset();
+ SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers;
synchronized (mLock) {
if (mStopped) {
return;
@@ -1159,6 +1147,8 @@
}
mustNotify = !mDisplayReadyLocked;
+
+ displayBrightnessFollowers = mDisplayBrightnessFollowers.clone();
}
int state = mDisplayStateController
@@ -1204,7 +1194,8 @@
? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
: AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
- final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
+ final boolean userSetBrightnessChanged = mDisplayBrightnessController
+ .updateUserSetScreenBrightness();
final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
@@ -1230,7 +1221,7 @@
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessState,
mBrightnessConfiguration,
- mLastUserSetScreenBrightness,
+ mDisplayBrightnessController.getLastUserSetScreenBrightness(),
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy,
mShouldResetShortTermModel);
@@ -1242,7 +1233,7 @@
}
boolean updateScreenBrightnessSetting = false;
-
+ float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness();
// Apply auto-brightness.
boolean slowChange = false;
if (Float.isNaN(brightnessState)) {
@@ -1253,14 +1244,14 @@
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
- if (isValidBrightnessValue(brightnessState)
+ if (BrightnessUtils.isValidBrightnessValue(brightnessState)
|| brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) {
// Use current auto-brightness value and slowly adjust to changes.
brightnessState = clampScreenBrightness(brightnessState);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
- updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState;
+ updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
mAppliedAutoBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
if (mScreenOffBrightnessSensorController != null) {
@@ -1298,9 +1289,10 @@
if (Float.isNaN(brightnessState) && autoBrightnessEnabled
&& mScreenOffBrightnessSensorController != null) {
brightnessState = mScreenOffBrightnessSensorController.getAutomaticScreenBrightness();
- if (isValidBrightnessValue(brightnessState)) {
+ if (BrightnessUtils.isValidBrightnessValue(brightnessState)) {
brightnessState = clampScreenBrightness(brightnessState);
- updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState;
+ updateScreenBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness()
+ != brightnessState;
mBrightnessReasonTemp.setReason(
BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR);
}
@@ -1308,8 +1300,8 @@
// Apply manual brightness.
if (Float.isNaN(brightnessState)) {
- brightnessState = clampScreenBrightness(mCurrentScreenBrightnessSetting);
- if (brightnessState != mCurrentScreenBrightnessSetting) {
+ brightnessState = clampScreenBrightness(currentBrightnessSetting);
+ if (brightnessState != currentBrightnessSetting) {
// The manually chosen screen brightness is outside of the currently allowed
// range (i.e., high-brightness-mode), make sure we tell the rest of the system
// by updating the setting.
@@ -1340,13 +1332,18 @@
mAppliedThrottling = false;
}
+ for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
+ DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
+ follower.setBrightnessToFollow(brightnessState, convertToNits(brightnessState));
+ }
+
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
// before applying the low power or dim transformations so that the slider
// accurately represents the full possible range, even if they range changes what
// it means in absolute terms.
- updateScreenBrightnessSetting(brightnessState);
+ mDisplayBrightnessController.updateScreenBrightnessSetting(brightnessState);
}
// Apply dimming by at least some minimum amount when user activity
@@ -1457,7 +1454,7 @@
final float currentBrightness = mPowerState.getScreenBrightness();
final float currentSdrBrightness = mPowerState.getSdrScreenBrightness();
- if (isValidBrightnessValue(animateValue)
+ if (BrightnessUtils.isValidBrightnessValue(animateValue)
&& (animateValue != currentBrightness
|| sdrAnimateValue != currentSdrBrightness)) {
if (initialRampSkip || hasBrightnessBuckets
@@ -1742,7 +1739,7 @@
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.update();
}
- }, mContext);
+ }, mHighBrightnessModeMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
@@ -1892,12 +1889,6 @@
mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
}
- // Checks whether the brightness is within the valid brightness range, not including off.
- private boolean isValidBrightnessValue(float brightness) {
- return brightness >= PowerManager.BRIGHTNESS_MIN
- && brightness <= PowerManager.BRIGHTNESS_MAX;
- }
-
private void animateScreenBrightness(float target, float sdrTarget, float rate) {
if (DEBUG) {
Slog.d(mTag, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget
@@ -2078,11 +2069,14 @@
}
private void handleSettingsChange(boolean userSwitch) {
- mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
+ mDisplayBrightnessController
+ .setPendingScreenBrightness(mDisplayBrightnessController
+ .getScreenBrightnessSetting());
mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
if (userSwitch) {
// Don't treat user switches as user initiated change.
- setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
+ mDisplayBrightnessController.setCurrentScreenBrightness(mDisplayBrightnessController
+ .getPendingScreenBrightness());
updateAutoBrightnessAdjustment();
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.resetShortTermModel();
@@ -2111,34 +2105,33 @@
@Override
public float getScreenBrightnessSetting() {
- float brightness = mBrightnessSetting.getBrightness();
- if (Float.isNaN(brightness)) {
- brightness = mScreenBrightnessDefault;
- }
- return clampAbsoluteBrightness(brightness);
+ return mDisplayBrightnessController.getScreenBrightnessSetting();
}
@Override
public void setBrightness(float brightnessValue) {
- // Update the setting, which will eventually call back into DPC to have us actually update
- // the display with the new value.
- mBrightnessSetting.setBrightness(brightnessValue);
+ mDisplayBrightnessController.setBrightness(brightnessValue);
}
- private void updateScreenBrightnessSetting(float brightnessValue) {
- if (!isValidBrightnessValue(brightnessValue)
- || brightnessValue == mCurrentScreenBrightnessSetting) {
- return;
- }
- setCurrentScreenBrightness(brightnessValue);
- mBrightnessSetting.setBrightness(brightnessValue);
+ @Override
+ public int getDisplayId() {
+ return mDisplayId;
}
- private void setCurrentScreenBrightness(float brightnessValue) {
- if (brightnessValue != mCurrentScreenBrightnessSetting) {
- mCurrentScreenBrightnessSetting = brightnessValue;
- postBrightnessChangeRunnable();
+ @Override
+ public void setBrightnessToFollow(float leadDisplayBrightness, float nits) {
+ if (mAutomaticBrightnessController == null || nits < 0) {
+ mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness);
+ } else {
+ float brightness = mAutomaticBrightnessController.convertToFloatScale(nits);
+ if (BrightnessUtils.isValidBrightnessValue(brightness)) {
+ mDisplayBrightnessController.setBrightnessToFollow(brightness);
+ } else {
+ // The device does not support nits
+ mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness);
+ }
}
+ sendUpdatePowerState();
}
private void putAutoBrightnessAdjustmentSetting(float adjustment) {
@@ -2164,28 +2157,6 @@
return true;
}
- // We want to return true if the user has set the screen brightness.
- // RBC on, off, and intensity changes will return false.
- // Slider interactions whilst in RBC will return true, just as when in non-rbc.
- private boolean updateUserSetScreenBrightness() {
- if ((Float.isNaN(mPendingScreenBrightnessSetting)
- || mPendingScreenBrightnessSetting < 0.0f)) {
- return false;
- }
- if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
- mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mDisplayBrightnessController
- .setTemporaryBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT);
- return false;
- }
- setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
- mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
- mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mDisplayBrightnessController
- .setTemporaryBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT);
- return true;
- }
-
private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated,
boolean hadUserDataPoint) {
final float brightnessInNits = convertToNits(brightness);
@@ -2213,6 +2184,27 @@
}
@Override
+ public void addDisplayBrightnessFollower(DisplayPowerControllerInterface follower) {
+ synchronized (mLock) {
+ mDisplayBrightnessFollowers.append(follower.getDisplayId(), follower);
+ }
+ sendUpdatePowerState();
+ }
+
+ @Override
+ public void clearDisplayBrightnessFollowers() {
+ SparseArray<DisplayPowerControllerInterface> followers;
+ synchronized (mLock) {
+ followers = mDisplayBrightnessFollowers.clone();
+ mDisplayBrightnessFollowers.clear();
+ }
+ for (int i = 0; i < followers.size(); i++) {
+ DisplayPowerControllerInterface follower = followers.valueAt(i);
+ follower.setBrightnessToFollow(PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1);
+ }
+ }
+
+ @Override
public void dump(final PrintWriter pw) {
synchronized (mLock) {
pw.println();
@@ -2230,7 +2222,6 @@
pw.println();
pw.println("Display Power Controller Configuration:");
- pw.println(" mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault);
pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
@@ -2261,9 +2252,6 @@
pw.println();
pw.println("Display Power Controller Thread State:");
pw.println(" mPowerRequest=" + mPowerRequest);
- pw.println(" mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness);
- pw.println(" mPendingScreenBrightnessSetting="
- + mPendingScreenBrightnessSetting);
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mBrightnessReason=" + mBrightnessReason);
pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
@@ -2380,11 +2368,6 @@
}
}
- private static float clampAbsoluteBrightness(float value) {
- return MathUtils.constrain(value, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX);
- }
-
private static float clampAutoBrightnessAdjustment(float value) {
return MathUtils.constrain(value, -1.0f, 1.0f);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index e750ee2..a95ac74 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -31,10 +31,14 @@
public interface DisplayPowerControllerInterface {
/**
- * Notified when the display is changed. We use this to apply any changes that might be needed
+ * Notified when the display is changed.
+ * We use this to apply any changes that might be needed
* when displays get swapped on foldable devices.
+ * We also pass the High brightness mode metadata like
+ * remaining time and hbm events for the corresponding
+ * physical display, to update the values correctly.
*/
- void onDisplayChanged();
+ void onDisplayChanged(HighBrightnessModeMetadata hbmInfo);
/**
* Unregisters all listeners and interrupts all running threads; halting future work.
@@ -157,4 +161,31 @@
* @param newUserId The new userId
*/
void onSwitchUser(int newUserId);
+
+ /**
+ * Get the ID of the display associated with this DPC.
+ * @return The display ID
+ */
+ int getDisplayId();
+
+ /**
+ * Set the brightness to follow if this is an additional display in a set of concurrent
+ * displays.
+ * @param leadDisplayBrightness The brightness of the lead display in the set of concurrent
+ * displays
+ * @param nits The brightness value in nits if the device supports nits
+ */
+ void setBrightnessToFollow(float leadDisplayBrightness, float nits);
+
+ /**
+ * Add an additional display that will copy the brightness value from this display. This is used
+ * when the device is in concurrent displays mode.
+ * @param follower The DPC that should copy the brightness value from this DPC
+ */
+ void addDisplayBrightnessFollower(DisplayPowerControllerInterface follower);
+
+ /**
+ * Clear all the additional displays following the brightness value of this display.
+ */
+ void clearDisplayBrightnessFollowers();
}
diff --git a/services/core/java/com/android/server/display/HbmEvent.java b/services/core/java/com/android/server/display/HbmEvent.java
new file mode 100644
index 0000000..5675e2f
--- /dev/null
+++ b/services/core/java/com/android/server/display/HbmEvent.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+
+/**
+ * Represents an event in which High Brightness Mode was enabled.
+ */
+class HbmEvent {
+ private long mStartTimeMillis;
+ private long mEndTimeMillis;
+
+ HbmEvent(long startTimeMillis, long endTimeMillis) {
+ this.mStartTimeMillis = startTimeMillis;
+ this.mEndTimeMillis = endTimeMillis;
+ }
+
+ public long getStartTimeMillis() {
+ return mStartTimeMillis;
+ }
+
+ public long getEndTimeMillis() {
+ return mEndTimeMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "HbmEvent: {startTimeMillis:" + mStartTimeMillis + ", endTimeMillis: "
+ + mEndTimeMillis + "}, total: "
+ + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]";
+ }
+}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index f98c7df..2c843a4 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -105,30 +105,23 @@
private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
/**
- * If HBM is currently running, this is the start time for the current HBM session.
+ * If HBM is currently running, this is the start time and set of all events,
+ * for the current HBM session.
*/
- private long mRunningStartTimeMillis = -1;
-
- /**
- * Queue of previous HBM-events ordered from most recent to least recent.
- * Meant to store only the events that fall into the most recent
- * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}.
- */
- private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>();
-
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata = null;
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
- Runnable hbmChangeCallback, Context context) {
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) {
this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
- brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context);
+ brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
- Runnable hbmChangeCallback, Context context) {
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) {
mInjector = injector;
mContext = context;
mClock = injector.getClock();
@@ -137,6 +130,7 @@
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
mHbmChangeCallback = hbmChangeCallback;
+ mHighBrightnessModeMetadata = hbmMetadata;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mRecalcRunnable = this::recalculateTimeAllowance;
@@ -222,19 +216,22 @@
// If we are starting or ending a high brightness mode session, store the current
// session in mRunningStartTimeMillis, or the old one in mEvents.
- final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1;
+ final long runningStartTime = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ final boolean wasHbmDrainingAvailableTime = runningStartTime != -1;
final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint
&& !mIsHdrLayerPresent;
if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) {
final long currentTime = mClock.uptimeMillis();
if (shouldHbmDrainAvailableTime) {
- mRunningStartTimeMillis = currentTime;
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime);
} else {
- mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime));
- mRunningStartTimeMillis = -1;
+ final HbmEvent hbmEvent = new HbmEvent(runningStartTime, currentTime);
+ mHighBrightnessModeMetadata.addHbmEvent(hbmEvent);
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(-1);
if (DEBUG) {
- Slog.d(TAG, "New HBM event: " + mEvents.peekFirst());
+ Slog.d(TAG, "New HBM event: "
+ + mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst());
}
}
}
@@ -260,6 +257,10 @@
mSettingsObserver.stopObserving();
}
+ void setHighBrightnessModeMetadata(HighBrightnessModeMetadata hbmInfo) {
+ mHighBrightnessModeMetadata = hbmInfo;
+ }
+
void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) {
mWidth = width;
@@ -316,20 +317,22 @@
pw.println(" mBrightnessMax=" + mBrightnessMax);
pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis()));
pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
- pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis));
+ pw.println(" mRunningStartTimeMillis="
+ + TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis()));
pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit);
pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode);
pw.println(" width*height=" + mWidth + "*" + mHeight);
pw.println(" mEvents=");
final long currentTime = mClock.uptimeMillis();
long lastStartTime = currentTime;
- if (mRunningStartTimeMillis != -1) {
- lastStartTime = dumpHbmEvent(pw, new HbmEvent(mRunningStartTimeMillis, currentTime));
+ long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ if (runningStartTimeMillis != -1) {
+ lastStartTime = dumpHbmEvent(pw, new HbmEvent(runningStartTimeMillis, currentTime));
}
- for (HbmEvent event : mEvents) {
- if (lastStartTime > event.endTimeMillis) {
+ for (HbmEvent event : mHighBrightnessModeMetadata.getHbmEventQueue()) {
+ if (lastStartTime > event.getEndTimeMillis()) {
pw.println(" event: [normal brightness]: "
- + TimeUtils.formatDuration(lastStartTime - event.endTimeMillis));
+ + TimeUtils.formatDuration(lastStartTime - event.getEndTimeMillis()));
}
lastStartTime = dumpHbmEvent(pw, event);
}
@@ -338,12 +341,12 @@
}
private long dumpHbmEvent(PrintWriter pw, HbmEvent event) {
- final long duration = event.endTimeMillis - event.startTimeMillis;
+ final long duration = event.getEndTimeMillis() - event.getStartTimeMillis();
pw.println(" event: ["
- + TimeUtils.formatUptime(event.startTimeMillis) + ", "
- + TimeUtils.formatUptime(event.endTimeMillis) + "] ("
+ + TimeUtils.formatUptime(event.getStartTimeMillis()) + ", "
+ + TimeUtils.formatUptime(event.getEndTimeMillis()) + "] ("
+ TimeUtils.formatDuration(duration) + ")");
- return event.startTimeMillis;
+ return event.getStartTimeMillis();
}
private boolean isCurrentlyAllowed() {
@@ -372,13 +375,15 @@
// First, lets see how much time we've taken for any currently running
// session of HBM.
- if (mRunningStartTimeMillis > 0) {
- if (mRunningStartTimeMillis > currentTime) {
+ long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ if (runningStartTimeMillis > 0) {
+ if (runningStartTimeMillis > currentTime) {
Slog.e(TAG, "Start time set to the future. curr: " + currentTime
- + ", start: " + mRunningStartTimeMillis);
- mRunningStartTimeMillis = currentTime;
+ + ", start: " + runningStartTimeMillis);
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime);
+ runningStartTimeMillis = currentTime;
}
- timeAlreadyUsed = currentTime - mRunningStartTimeMillis;
+ timeAlreadyUsed = currentTime - runningStartTimeMillis;
}
if (DEBUG) {
@@ -387,18 +392,19 @@
// Next, lets iterate through the history of previous sessions and add those times.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
- Iterator<HbmEvent> it = mEvents.iterator();
+ Iterator<HbmEvent> it = mHighBrightnessModeMetadata.getHbmEventQueue().iterator();
while (it.hasNext()) {
final HbmEvent event = it.next();
// If this event ended before the current Timing window, discard forever and ever.
- if (event.endTimeMillis < windowstartTimeMillis) {
+ if (event.getEndTimeMillis() < windowstartTimeMillis) {
it.remove();
continue;
}
- final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis);
- timeAlreadyUsed += event.endTimeMillis - startTimeMillis;
+ final long startTimeMillis = Math.max(event.getStartTimeMillis(),
+ windowstartTimeMillis);
+ timeAlreadyUsed += event.getEndTimeMillis() - startTimeMillis;
}
if (DEBUG) {
@@ -425,17 +431,18 @@
// Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or
// brightness change doesn't happen before then.
long nextTimeout = -1;
+ final ArrayDeque<HbmEvent> hbmEvents = mHighBrightnessModeMetadata.getHbmEventQueue();
if (mBrightness > mHbmData.transitionPoint) {
// if we're in high-lux now, timeout when we run out of allowed time.
nextTimeout = currentTime + remainingTime;
- } else if (!mIsTimeAvailable && mEvents.size() > 0) {
+ } else if (!mIsTimeAvailable && hbmEvents.size() > 0) {
// If we are not allowed...timeout when the oldest event moved outside of the timing
// window by at least minTime. Basically, we're calculating the soonest time we can
// get {@code timeMinMillis} back to us.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
- final HbmEvent lastEvent = mEvents.peekLast();
+ final HbmEvent lastEvent = hbmEvents.peekLast();
final long startTimePlusMinMillis =
- Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
+ Math.max(windowstartTimeMillis, lastEvent.getStartTimeMillis())
+ mHbmData.timeMinMillis;
final long timeWhenMinIsGainedBack =
currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime;
@@ -459,9 +466,10 @@
+ ", mUnthrottledBrightness: " + mUnthrottledBrightness
+ ", mThrottlingReason: "
+ BrightnessInfo.briMaxReasonToString(mThrottlingReason)
- + ", RunningStartTimeMillis: " + mRunningStartTimeMillis
+ + ", RunningStartTimeMillis: "
+ + mHighBrightnessModeMetadata.getRunningStartTimeMillis()
+ ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1)
- + ", events: " + mEvents);
+ + ", events: " + hbmEvents);
}
if (nextTimeout != -1) {
@@ -588,25 +596,6 @@
}
}
- /**
- * Represents an event in which High Brightness Mode was enabled.
- */
- private static class HbmEvent {
- public long startTimeMillis;
- public long endTimeMillis;
-
- HbmEvent(long startTimeMillis, long endTimeMillis) {
- this.startTimeMillis = startTimeMillis;
- this.endTimeMillis = endTimeMillis;
- }
-
- @Override
- public String toString() {
- return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: "
- + ((endTimeMillis - startTimeMillis) / 1000) + "]";
- }
- }
-
@VisibleForTesting
class HdrListener extends SurfaceControlHdrLayerInfoListener {
@Override
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java
new file mode 100644
index 0000000..37234ff
--- /dev/null
+++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import java.util.ArrayDeque;
+
+
+/**
+ * Represents High Brightness Mode metadata associated
+ * with a specific internal physical display.
+ * Required for separately storing data like time information,
+ * and related events when display was in HBM mode per
+ * physical internal display.
+ */
+class HighBrightnessModeMetadata {
+ /**
+ * Queue of previous HBM-events ordered from most recent to least recent.
+ * Meant to store only the events that fall into the most recent
+ * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}.
+ */
+ private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>();
+
+ /**
+ * If HBM is currently running, this is the start time for the current HBM session.
+ */
+ private long mRunningStartTimeMillis = -1;
+
+ public long getRunningStartTimeMillis() {
+ return mRunningStartTimeMillis;
+ }
+
+ public void setRunningStartTimeMillis(long setTime) {
+ mRunningStartTimeMillis = setTime;
+ }
+
+ public ArrayDeque<HbmEvent> getHbmEventQueue() {
+ return mEvents;
+ }
+
+ public void addHbmEvent(HbmEvent hbmEvent) {
+ mEvents.addFirst(hbmEvent);
+ }
+}
+
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index a952004..d7ae269 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -38,7 +38,8 @@
public static final int REASON_TEMPORARY = 7;
public static final int REASON_BOOST = 8;
public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9;
- public static final int REASON_MAX = REASON_SCREEN_OFF_BRIGHTNESS_SENSOR;
+ public static final int REASON_FOLLOWER = 10;
+ public static final int REASON_MAX = REASON_FOLLOWER;
public static final int MODIFIER_DIMMED = 0x1;
public static final int MODIFIER_LOW_POWER = 0x2;
@@ -193,6 +194,8 @@
return "boost";
case REASON_SCREEN_OFF_BRIGHTNESS_SENSOR:
return "screen_off_brightness_sensor";
+ case REASON_FOLLOWER:
+ return "follower";
default:
return Integer.toString(reason);
}
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
index fd4e296..d5aeba1 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
@@ -17,6 +17,7 @@
package com.android.server.display.brightness;
import android.os.PowerManager;
+import android.util.MathUtils;
import com.android.server.display.DisplayBrightnessState;
@@ -33,6 +34,14 @@
}
/**
+ * Clamps the brightness value in the maximum and the minimum brightness range
+ */
+ public static float clampAbsoluteBrightness(float value) {
+ return MathUtils.constrain(value, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX);
+ }
+
+ /**
* A utility to construct the DisplayBrightnessState
*/
public static DisplayBrightnessState constructDisplayBrightnessState(
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index bdc8d9d..13fcff3 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -18,9 +18,12 @@
import android.content.Context;
import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
import android.util.IndentingPrintWriter;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.BrightnessSetting;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
@@ -31,19 +34,67 @@
* display. Applies the chosen brightness.
*/
public final class DisplayBrightnessController {
+ // The ID of the display tied to this DisplayBrightnessController
private final int mDisplayId;
+
+ // The lock which is to be used to synchronize the resources being used in this class
+ private final Object mLock = new Object();
+
+ // The default screen brightness to be used when no value is available in BrightnessSetting.
+ private final float mScreenBrightnessDefault;
+
+ // This is used to persist the changes happening to the brightness.
+ private final BrightnessSetting mBrightnessSetting;
+
+ // A runnable to update the clients registered via DisplayManagerGlobal
+ // .EVENT_DISPLAY_BRIGHTNESS_CHANGED about the brightness change. Called when
+ // mCurrentScreenBrightness is updated.
+ private Runnable mOnBrightnessChangeRunnable;
+
+ // The screen brightness that has changed but not taken effect yet. If this is different
+ // from the current screen brightness then this is coming from something other than us
+ // and should be considered a user interaction.
+ @GuardedBy("mLock")
+ private float mPendingScreenBrightness;
+
+ // The last observed screen brightness, either set by us or by the settings app on
+ // behalf of the user.
+ @GuardedBy("mLock")
+ private float mCurrentScreenBrightness;
+
+ // The last brightness that was set by the user and not temporary. Set to
+ // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded.
+ @GuardedBy("mLock")
+ private float mLastUserSetScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
+ // The listener which is to be notified everytime there is a change in the brightness in the
+ // BrightnessSetting.
+ private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener;
+
// Selects an appropriate strategy based on the request provided by the clients.
+ @GuardedBy("mLock")
private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
+
+ // Currently selected DisplayBrightnessStrategy.
+ @GuardedBy("mLock")
private DisplayBrightnessStrategy mDisplayBrightnessStrategy;
/**
* The constructor of DisplayBrightnessController.
*/
- public DisplayBrightnessController(Context context, Injector injector, int displayId) {
+ public DisplayBrightnessController(Context context, Injector injector, int displayId,
+ float defaultScreenBrightness, BrightnessSetting brightnessSetting,
+ Runnable onBrightnessChangeRunnable) {
if (injector == null) {
injector = new Injector();
}
mDisplayId = displayId;
+ // TODO: b/186428377 update brightness setting when display changes
+ mBrightnessSetting = brightnessSetting;
+ mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mCurrentScreenBrightness = getScreenBrightnessSetting();
+ mOnBrightnessChangeRunnable = onBrightnessChangeRunnable;
+ mScreenBrightnessDefault = BrightnessUtils.clampAbsoluteBrightness(defaultScreenBrightness);
mDisplayBrightnessStrategySelector = injector.getDisplayBrightnessStrategySelector(context,
displayId);
}
@@ -61,25 +112,30 @@
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
int targetDisplayState) {
- mDisplayBrightnessStrategy =
- mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
- targetDisplayState);
- return mDisplayBrightnessStrategy.updateBrightness(displayPowerRequest);
+ synchronized (mLock) {
+ mDisplayBrightnessStrategy = mDisplayBrightnessStrategySelector.selectStrategy(
+ displayPowerRequest, targetDisplayState);
+ return mDisplayBrightnessStrategy.updateBrightness(displayPowerRequest);
+ }
}
/**
* Sets the temporary brightness
*/
public void setTemporaryBrightness(Float temporaryBrightness) {
- mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()
- .setTemporaryScreenBrightness(temporaryBrightness);
+ synchronized (mLock) {
+ setTemporaryBrightnessLocked(temporaryBrightness);
+ }
}
/**
- * Returns the current selected DisplayBrightnessStrategy
+ * Sets the brightness to follow
*/
- public DisplayBrightnessStrategy getCurrentDisplayBrightnessStrategy() {
- return mDisplayBrightnessStrategy;
+ public void setBrightnessToFollow(Float brightnessToFollow) {
+ synchronized (mLock) {
+ mDisplayBrightnessStrategySelector.getFollowerDisplayBrightnessStrategy()
+ .setBrightnessToFollow(brightnessToFollow);
+ }
}
/**
@@ -87,7 +143,140 @@
* brightness when dozing
*/
public boolean isAllowAutoBrightnessWhileDozingConfig() {
- return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozingConfig();
+ synchronized (mLock) {
+ return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozingConfig();
+ }
+ }
+
+ /**
+ * Sets the current screen brightness to the supplied value, and notifies all the listeners
+ * requesting for change events on brightness change.
+ */
+ public void setCurrentScreenBrightness(float brightnessValue) {
+ synchronized (mLock) {
+ if (brightnessValue != mCurrentScreenBrightness) {
+ mCurrentScreenBrightness = brightnessValue;
+ mOnBrightnessChangeRunnable.run();
+ }
+ }
+ }
+
+ /**
+ * Returns the last observed screen brightness.
+ */
+ public float getCurrentBrightness() {
+ synchronized (mLock) {
+ return mCurrentScreenBrightness;
+ }
+ }
+
+ /**
+ * Returns the screen brightness which has changed but has not taken any effect so far.
+ */
+ public float getPendingScreenBrightness() {
+ synchronized (mLock) {
+ return mPendingScreenBrightness;
+ }
+ }
+
+ /**
+ * Sets the pending screen brightness setting, representing a value which is requested, but not
+ * yet processed.
+ * @param brightnessValue The value to which the pending screen brightness is to be set.
+ */
+ public void setPendingScreenBrightness(float brightnessValue) {
+ synchronized (mLock) {
+ mPendingScreenBrightness = brightnessValue;
+ }
+ }
+
+ /**
+ * We want to return true if the user has set the screen brightness.
+ * RBC on, off, and intensity changes will return false.
+ * Slider interactions whilst in RBC will return true, just as when in non-rbc.
+ */
+ public boolean updateUserSetScreenBrightness() {
+ synchronized (mLock) {
+ if (!BrightnessUtils.isValidBrightnessValue(mPendingScreenBrightness)) {
+ return false;
+ }
+ if (mCurrentScreenBrightness == mPendingScreenBrightness) {
+ mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ return false;
+ }
+ setCurrentScreenBrightness(mPendingScreenBrightness);
+ mLastUserSetScreenBrightness = mPendingScreenBrightness;
+ mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ return true;
+ }
+ }
+
+ /**
+ * Registers the BrightnessSettingListener with the BrightnessSetting, which will be notified
+ * everytime there is a change in the brightness.
+ */
+ public void registerBrightnessSettingChangeListener(
+ BrightnessSetting.BrightnessSettingListener brightnessSettingListener) {
+ mBrightnessSettingListener = brightnessSettingListener;
+ mBrightnessSetting.registerListener(mBrightnessSettingListener);
+ }
+
+ /**
+ * Returns the last user set brightness which is not temporary.
+ */
+ public float getLastUserSetScreenBrightness() {
+ synchronized (mLock) {
+ return mLastUserSetScreenBrightness;
+ }
+ }
+
+ /**
+ * Returns the current screen brightnessSetting which is responsible for saving the brightness
+ * in the persistent store
+ */
+ public float getScreenBrightnessSetting() {
+ float brightness = mBrightnessSetting.getBrightness();
+ synchronized (mLock) {
+ if (Float.isNaN(brightness)) {
+ brightness = mScreenBrightnessDefault;
+ }
+ return BrightnessUtils.clampAbsoluteBrightness(brightness);
+ }
+ }
+
+ /**
+ * Notifies the brightnessSetting to persist the supplied brightness value.
+ */
+ public void setBrightness(float brightnessValue) {
+ // Update the setting, which will eventually call back into DPC to have us actually
+ // update the display with the new value.
+ mBrightnessSetting.setBrightness(brightnessValue);
+ }
+
+ /**
+ * Sets the current screen brightness, and notifies the BrightnessSetting about the change.
+ */
+ public void updateScreenBrightnessSetting(float brightnessValue) {
+ synchronized (mLock) {
+ if (!BrightnessUtils.isValidBrightnessValue(brightnessValue)
+ || brightnessValue == mCurrentScreenBrightness) {
+ return;
+ }
+ setCurrentScreenBrightness(brightnessValue);
+ setBrightness(brightnessValue);
+ }
+ }
+
+ /**
+ * Stops the associated listeners when the display is stopped. Invoked when the {@link
+ * #mDisplayId} is being removed.
+ */
+ public void stop() {
+ if (mBrightnessSetting != null) {
+ mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
+ }
}
/**
@@ -99,12 +288,19 @@
writer.println();
writer.println("DisplayBrightnessController:");
writer.println(" mDisplayId=: " + mDisplayId);
- if (mDisplayBrightnessStrategy != null) {
- writer.println(" Last selected DisplayBrightnessStrategy= "
- + mDisplayBrightnessStrategy.getName());
+ writer.println(" mScreenBrightnessDefault=" + mScreenBrightnessDefault);
+ synchronized (mLock) {
+ writer.println(" mPendingScreenBrightness=" + mPendingScreenBrightness);
+ writer.println(" mCurrentScreenBrightness=" + mCurrentScreenBrightness);
+ writer.println(" mLastUserSetScreenBrightness="
+ + mLastUserSetScreenBrightness);
+ if (mDisplayBrightnessStrategy != null) {
+ writer.println(" Last selected DisplayBrightnessStrategy= "
+ + mDisplayBrightnessStrategy.getName());
+ }
+ IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
+ mDisplayBrightnessStrategySelector.dump(ipw);
}
- IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
- mDisplayBrightnessStrategySelector.dump(ipw);
}
@VisibleForTesting
@@ -114,4 +310,26 @@
return new DisplayBrightnessStrategySelector(context, /* injector= */ null, displayId);
}
}
+
+ @VisibleForTesting
+ BrightnessSetting.BrightnessSettingListener getBrightnessSettingListenerLocked() {
+ return mBrightnessSettingListener;
+ }
+
+ /**
+ * Returns the current selected DisplayBrightnessStrategy
+ */
+ @VisibleForTesting
+ DisplayBrightnessStrategy getCurrentDisplayBrightnessStrategyLocked() {
+ synchronized (mLock) {
+ return mDisplayBrightnessStrategy;
+ }
+ }
+
+ private void setTemporaryBrightnessLocked(float temporaryBrightness) {
+ synchronized (mLock) {
+ mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()
+ .setTemporaryScreenBrightness(temporaryBrightness);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 7d05f13..02ca2d3 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -28,6 +28,7 @@
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
@@ -55,6 +56,8 @@
private final TemporaryBrightnessStrategy mTemporaryBrightnessStrategy;
// The brightness strategy used to manage the brightness state when boost is requested
private final BoostBrightnessStrategy mBoostBrightnessStrategy;
+ // The brightness strategy used for additional displays
+ private final FollowerBrightnessStrategy mFollowerBrightnessStrategy;
// The brightness strategy used to manage the brightness state when the request is invalid.
private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
@@ -76,6 +79,7 @@
mOverrideBrightnessStrategy = injector.getOverrideBrightnessStrategy();
mTemporaryBrightnessStrategy = injector.getTemporaryBrightnessStrategy();
mBoostBrightnessStrategy = injector.getBoostBrightnessStrategy();
+ mFollowerBrightnessStrategy = injector.getFollowerBrightnessStrategy(displayId);
mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
R.bool.config_allowAutoBrightnessWhileDozing);
@@ -93,10 +97,13 @@
DisplayBrightnessStrategy displayBrightnessStrategy = mInvalidBrightnessStrategy;
if (targetDisplayState == Display.STATE_OFF) {
displayBrightnessStrategy = mScreenOffBrightnessStrategy;
- } else if (displayPowerRequest.boostScreenBrightness) {
- displayBrightnessStrategy = mBoostBrightnessStrategy;
} else if (shouldUseDozeBrightnessStrategy(displayPowerRequest)) {
displayBrightnessStrategy = mDozeBrightnessStrategy;
+ } else if (BrightnessUtils.isValidBrightnessValue(
+ mFollowerBrightnessStrategy.getBrightnessToFollow())) {
+ displayBrightnessStrategy = mFollowerBrightnessStrategy;
+ } else if (displayPowerRequest.boostScreenBrightness) {
+ displayBrightnessStrategy = mBoostBrightnessStrategy;
} else if (BrightnessUtils
.isValidBrightnessValue(displayPowerRequest.screenBrightnessOverride)) {
displayBrightnessStrategy = mOverrideBrightnessStrategy;
@@ -119,6 +126,10 @@
return mTemporaryBrightnessStrategy;
}
+ public FollowerBrightnessStrategy getFollowerDisplayBrightnessStrategy() {
+ return mFollowerBrightnessStrategy;
+ }
+
/**
* Returns a boolean flag indicating if the light sensor is to be used to decide the screen
* brightness when dozing
@@ -180,6 +191,10 @@
return new BoostBrightnessStrategy();
}
+ FollowerBrightnessStrategy getFollowerBrightnessStrategy(int displayId) {
+ return new FollowerBrightnessStrategy(displayId);
+ }
+
InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
return new InvalidBrightnessStrategy();
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
index 475ef50..0cf234b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -35,7 +35,8 @@
@Override
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
- // Todo(brup): Introduce a validator class and add validations before setting the brightness
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
DisplayBrightnessState displayBrightnessState =
BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_BOOST,
PowerManager.BRIGHTNESS_MAX,
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
index 0bc900b..98075f9 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -30,7 +30,8 @@
@Override
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
- // Todo(brup): Introduce a validator class and add validations before setting the brightness
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_DOZE,
displayPowerRequest.dozeScreenBrightness, displayPowerRequest.dozeScreenBrightness);
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
new file mode 100644
index 0000000..fe684a4
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the brightness of an additional display that copies the brightness value from the lead
+ * display when the device is using concurrent displays.
+ */
+public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy {
+
+ // The ID of the LogicalDisplay using this strategy.
+ private final int mDisplayId;
+
+ // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no brightness to follow set.
+ private float mBrightnessToFollow;
+
+ public FollowerBrightnessStrategy(int displayId) {
+ mDisplayId = displayId;
+ mBrightnessToFollow = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
+
+ @Override
+ public DisplayBrightnessState updateBrightness(
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
+ return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_FOLLOWER,
+ mBrightnessToFollow, mBrightnessToFollow);
+ }
+
+ @Override
+ public String getName() {
+ return "FollowerBrightnessStrategy";
+ }
+
+ public float getBrightnessToFollow() {
+ return mBrightnessToFollow;
+ }
+
+ public void setBrightnessToFollow(float brightnessToFollow) {
+ mBrightnessToFollow = brightnessToFollow;
+ }
+
+ /**
+ * Dumps the state of this class.
+ */
+ public void dump(PrintWriter writer) {
+ writer.println("FollowerBrightnessStrategy:");
+ writer.println(" mDisplayId=" + mDisplayId);
+ writer.println(" mBrightnessToFollow:" + mBrightnessToFollow);
+ }
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index f03f036..6d3830a 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -29,7 +29,8 @@
@Override
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
- // Todo(brup): Introduce a validator class and add validations before setting the brightness
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_OVERRIDE,
displayPowerRequest.screenBrightnessOverride,
displayPowerRequest.screenBrightnessOverride);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
index 396fa06..ee5e066 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -30,7 +30,8 @@
@Override
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
- // Todo(brup): Introduce a validator class and add validations before setting the brightness
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_SCREEN_OFF,
PowerManager.BRIGHTNESS_OFF_FLOAT,
PowerManager.BRIGHTNESS_OFF_FLOAT);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index 7d759ca..d97415d 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -43,7 +43,8 @@
@Override
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
- // Todo(brup): Introduce a validator class and add validations before setting the brightness
+ // Todo(b/241308599): Introduce a validator class and add validations before setting
+ // the brightness
DisplayBrightnessState displayBrightnessState =
BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_TEMPORARY,
mTemporaryScreenBrightness,
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index c1780a3..e5357f6 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -16,6 +16,9 @@
package com.android.server.dreams;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+
+import android.app.ActivityTaskManager;
import android.app.BroadcastOptions;
import android.content.ComponentName;
import android.content.Context;
@@ -62,6 +65,7 @@
private final Context mContext;
private final Handler mHandler;
private final Listener mListener;
+ private final ActivityTaskManager mActivityTaskManager;
private final Intent mDreamingStartedIntent = new Intent(Intent.ACTION_DREAMING_STARTED)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -89,6 +93,7 @@
mContext = context;
mHandler = handler;
mListener = listener;
+ mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mCloseNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mCloseNotificationShadeIntent.putExtra("reason", "dream");
}
@@ -272,6 +277,9 @@
mSentStartBroadcast = false;
}
+ mActivityTaskManager.removeRootTasksWithActivityTypes(
+ new int[] {ACTIVITY_TYPE_DREAM});
+
mListener.onDreamStopped(dream.mToken);
}
} finally {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index c47d749..a4d2d03 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -462,7 +462,7 @@
}
protected void requestStopDreamFromShell() {
- stopDreamInternal(true, "stopping dream from shell");
+ stopDreamInternal(false, "stopping dream from shell");
}
private void stopDreamInternal(boolean immediate, String reason) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index ceb8785..376e6f8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -38,6 +38,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.stats.hdmi.HdmiStatsEnums;
import android.util.Slog;
@@ -380,7 +381,7 @@
* Configures the TV panel device wakeup behaviour in standby mode when it receives an OTP
* (One Touch Play) from a source device.
*
- * @param value If true, the TV device will wake up when OTP is received and if false, the TV
+ * @param enabled If true, the TV device will wake up when OTP is received and if false, the TV
* device will not wake up for an OTP.
*/
@ServiceThreadOnly
@@ -393,7 +394,7 @@
/**
* Switch to enable or disable CEC on the device.
*
- * @param value If true, the device will have all CEC functionalities and if false, the device
+ * @param enabled If true, the device will have all CEC functionalities and if false, the device
* will not perform any CEC functions.
*/
@ServiceThreadOnly
@@ -406,8 +407,8 @@
/**
* Configures the module that processes CEC messages - the Android framework or the HAL.
*
- * @param value If true, the Android framework will actively process CEC messages and if false,
- * only the HAL will process the CEC messages.
+ * @param enabled If true, the Android framework will actively process CEC messages.
+ * If false, only the HAL will process the CEC messages.
*/
@ServiceThreadOnly
void enableSystemCecControl(boolean enabled) {
@@ -423,9 +424,8 @@
@ServiceThreadOnly
void setHpdSignalType(@Constants.HpdSignalType int signal, int portId) {
assertRunOnServiceThread();
- // Stub.
- // TODO: bind to native.
- // TODO: handle error return values here, with logging.
+ HdmiLogger.debug("setHpdSignalType: portId %b, signal %b", portId, signal);
+ mNativeWrapperImpl.nativeSetHpdSignalType(signal, portId);
}
/**
@@ -436,9 +436,8 @@
@Constants.HpdSignalType
int getHpdSignalType(int portId) {
assertRunOnServiceThread();
- // Stub.
- // TODO: bind to native.
- return Constants.HDMI_HPD_TYPE_PHYSICAL;
+ HdmiLogger.debug("getHpdSignalType: portId %b ", portId);
+ return mNativeWrapperImpl.nativeGetHpdSignalType(portId);
}
/**
@@ -906,6 +905,8 @@
void nativeSetLanguage(String language);
void nativeEnableAudioReturnChannel(int port, boolean flag);
boolean nativeIsConnected(int port);
+ void nativeSetHpdSignalType(int signal, int portId);
+ int nativeGetHpdSignalType(int portId);
}
private static final class NativeWrapperImplAidl
@@ -1096,15 +1097,15 @@
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.length];
int i = 0;
for (android.hardware.tv.hdmi.connection.HdmiPortInfo portInfo : hdmiPortInfos) {
- hdmiPortInfo[i] =
- new HdmiPortInfo(
+ hdmiPortInfo[i] = new HdmiPortInfo.Builder(
portInfo.portId,
portInfo.type,
- portInfo.physicalAddress,
- portInfo.cecSupported,
- false,
- portInfo.arcSupported,
- false);
+ portInfo.physicalAddress)
+ .setCecSupported(portInfo.cecSupported)
+ .setMhlSupported(false)
+ .setArcSupported(portInfo.arcSupported)
+ .setEarcSupported(portInfo.eArcSupported)
+ .build();
i++;
}
return hdmiPortInfo;
@@ -1123,6 +1124,34 @@
return false;
}
}
+
+ @Override
+ public void nativeSetHpdSignalType(int signal, int portId) {
+ try {
+ // TODO(b/266178786) add portId to the HAL method
+ mHdmiConnection.setHpdSignal((byte) signal);
+ } catch (ServiceSpecificException sse) {
+ HdmiLogger.error(
+ "Could not set HPD signal type for portId " + portId + " to " + signal
+ + ". Error: ", sse.errorCode);
+ } catch (RemoteException e) {
+ HdmiLogger.error(
+ "Could not set HPD signal type for portId " + portId + " to " + signal
+ + ". Exception: ", e);
+ }
+ }
+
+ @Override
+ public int nativeGetHpdSignalType(int portId) {
+ try {
+ // TODO(b/266178786) add portId to the HAL method
+ return mHdmiConnection.getHpdSignal();
+ } catch (RemoteException e) {
+ HdmiLogger.error(
+ "Could not get HPD signal type for portId " + portId + ". Exception: ", e);
+ return Constants.HDMI_HPD_TYPE_PHYSICAL;
+ }
+ }
}
private static final class NativeWrapperImpl11 implements NativeWrapper,
@@ -1260,13 +1289,15 @@
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()];
int i = 0;
for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) {
- hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId,
+ hdmiPortInfo[i] = new HdmiPortInfo.Builder(
+ portInfo.portId,
portInfo.type,
- portInfo.physicalAddress,
- portInfo.cecSupported,
- false,
- portInfo.arcSupported,
- false);
+ portInfo.physicalAddress)
+ .setCecSupported(portInfo.cecSupported)
+ .setMhlSupported(false)
+ .setArcSupported(portInfo.arcSupported)
+ .setEarcSupported(false)
+ .build();
i++;
}
return hdmiPortInfo;
@@ -1326,6 +1357,19 @@
return false;
}
}
+
+ @Override
+ public void nativeSetHpdSignalType(int signal, int portId) {
+ HdmiLogger.error(
+ "Failed to set HPD signal type: not supported by HAL.");
+ }
+
+ @Override
+ public int nativeGetHpdSignalType(int portId) {
+ HdmiLogger.error(
+ "Failed to get HPD signal type: not supported by HAL.");
+ return Constants.HDMI_HPD_TYPE_PHYSICAL;
+ }
}
private static final class NativeWrapperImpl implements NativeWrapper,
@@ -1442,13 +1486,15 @@
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()];
int i = 0;
for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) {
- hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId,
+ hdmiPortInfo[i] = new HdmiPortInfo.Builder(
+ portInfo.portId,
portInfo.type,
- portInfo.physicalAddress,
- portInfo.cecSupported,
- false,
- portInfo.arcSupported,
- false);
+ portInfo.physicalAddress)
+ .setCecSupported(portInfo.cecSupported)
+ .setMhlSupported(false)
+ .setArcSupported(portInfo.arcSupported)
+ .setEarcSupported(false)
+ .build();
i++;
}
return hdmiPortInfo;
@@ -1510,6 +1556,19 @@
}
@Override
+ public void nativeSetHpdSignalType(int signal, int portId) {
+ HdmiLogger.error(
+ "Failed to set HPD signal type: not supported by HAL.");
+ }
+
+ @Override
+ public int nativeGetHpdSignalType(int portId) {
+ HdmiLogger.error(
+ "Failed to get HPD signal type: not supported by HAL.");
+ return Constants.HDMI_HPD_TYPE_PHYSICAL;
+ }
+
+ @Override
public void serviceDied(long cookie) {
if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting");
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index a57292a..18a69c8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -469,9 +469,12 @@
ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
for (HdmiPortInfo info : cecPortInfo) {
if (mhlSupportedPorts.contains(info.getId())) {
- result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(),
- info.isCecSupported(), true, info.isArcSupported(),
- info.isEarcSupported()));
+ result.add(new HdmiPortInfo.Builder(info.getId(), info.getType(), info.getAddress())
+ .setCecSupported(info.isCecSupported())
+ .setMhlSupported(true)
+ .setArcSupported(info.isArcSupported())
+ .setEarcSupported(info.isEarcSupported())
+ .build());
} else {
result.add(info);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 31b8ef2..48e0c30 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -114,6 +114,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.FeatureFlagUtils;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -2503,6 +2504,28 @@
return mRecoverableKeyStoreManager.getKey(alias);
}
+ /**
+ * Starts a session to verify lock screen credentials provided by a remote device.
+ */
+ public void startRemoteLockscreenValidation() {
+ if (!FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API)) {
+ throw new UnsupportedOperationException("Under development");
+ }
+ mRecoverableKeyStoreManager.startRemoteLockscreenValidation();
+ }
+
+ /**
+ * Verifies credentials guess from a remote device.
+ */
+ public void validateRemoteLockscreen(@NonNull byte[] encryptedCredential) {
+ if (!FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API)) {
+ throw new UnsupportedOperationException("Under development");
+ }
+ mRecoverableKeyStoreManager.validateRemoteLockscreen(encryptedCredential);
+ }
+
// Reading these settings needs the contacts permission
private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index e620c80..7c80d8a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -965,6 +965,35 @@
}
}
+ /**
+ * Starts a session to verify lock screen credentials provided by a remote device.
+ */
+ public void startRemoteLockscreenValidation() {
+ checkVerifyRemoteLockscreenPermission();
+ // TODO(b/254335492): Create session in memory
+ return;
+ }
+
+ /**
+ * Verifies encrypted credentials guess from a remote device.
+ */
+ public void validateRemoteLockscreen(@NonNull byte[] encryptedCredential) {
+ checkVerifyRemoteLockscreenPermission();
+ // TODO(b/254335492): Decrypt and verify credentials
+ return;
+ }
+
+ private void checkVerifyRemoteLockscreenPermission() {
+ // TODO(b/254335492): Check new system permission
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.RECOVER_KEYSTORE,
+ "Caller " + Binder.getCallingUid()
+ + " doesn't have verifyRemoteLockscreen permission.");
+ int userId = UserHandle.getCallingUserId();
+ int uid = Binder.getCallingUid();
+ mCleanupManager.registerRecoveryAgent(userId, uid);
+ }
+
private void checkRecoverKeyStorePermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.RECOVER_KEYSTORE,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index 1dffcf9..4a17e9a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -78,6 +78,18 @@
return new RecoverableKeyStoreDb(helper);
}
+ /**
+ * A new instance, storing the database in the user directory of {@code context}.
+ *
+ * @hide
+ */
+ public static RecoverableKeyStoreDb newInstance(Context context, int version) {
+ RecoverableKeyStoreDbHelper helper = new RecoverableKeyStoreDbHelper(context, version);
+ helper.setWriteAheadLoggingEnabled(true);
+ helper.setIdleConnectionTimeout(IDLE_TIMEOUT_SECONDS);
+ return new RecoverableKeyStoreDb(helper);
+ }
+
private RecoverableKeyStoreDb(RecoverableKeyStoreDbHelper keyStoreDbHelper) {
this.mKeyStoreDbHelper = keyStoreDbHelper;
this.mTestOnlyInsecureCertificateHelper = new TestOnlyInsecureCertificateHelper();
@@ -389,7 +401,55 @@
ensureUserMetadataEntryExists(userId);
return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
+ }
+ /**
+ * Sets the {@code badGuessCounter} for the user {@code userId}.
+ *
+ * @return The number of updated rows.
+ */
+ public long setBadRemoteGuessCounter(int userId, int badGuessCounter) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);
+ values.put(UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER, badGuessCounter);
+ String selection = UserMetadataEntry.COLUMN_NAME_USER_ID + " = ?";
+ String[] selectionArguments = new String[] {String.valueOf(userId)};
+
+ ensureUserMetadataEntryExists(userId);
+ return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
+ }
+
+ /**
+ * Returns the number of invalid remote lock screen guesses for the user {@code userId}.
+ */
+ public int getBadRemoteGuessCounter(int userId) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
+ String[] projection = {
+ UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER};
+ String selection =
+ UserMetadataEntry.COLUMN_NAME_USER_ID + " = ?";
+ String[] selectionArguments = {
+ Integer.toString(userId)};
+
+ try (
+ Cursor cursor = db.query(
+ UserMetadataEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ if (cursor.getCount() == 0) {
+ return 0;
+ }
+ cursor.moveToFirst();
+ return cursor.getInt(
+ cursor.getColumnIndexOrThrow(
+ UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER));
+ }
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index e79d117..684f49f 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -98,6 +98,11 @@
* Serial number for the user which can not be reused. Default value is {@code -1}.
*/
static final String COLUMN_NAME_USER_SERIAL_NUMBER = "user_serial_number";
+
+ /**
+ * Number of invalid lockscreen credentials guess from a remote device.
+ */
+ static final String COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER = "bad_remote_guess_counter";
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 3e7b0a7..fa53a607 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -32,7 +32,10 @@
class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
private static final String TAG = "RecoverableKeyStoreDbHp";
- static final int DATABASE_VERSION = 6; // Added user id serial number.
+ // v6 - added user id serial number.
+ static final int DATABASE_VERSION = 6;
+ // v7 - added bad guess counter for remote LSKF check;
+ static final int DATABASE_VERSION_7 = 7;
private static final String DATABASE_NAME = "recoverablekeystore.db";
private static final String SQL_CREATE_KEYS_ENTRY =
@@ -57,6 +60,16 @@
+ UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER,"
+ UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER + " INTEGER DEFAULT -1)";
+
+ private static final String SQL_CREATE_USER_METADATA_ENTRY_FOR_V7 =
+ "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
+ + UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
+ + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
+ + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER,"
+ + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER + " INTEGER DEFAULT -1,"
+ + UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER
+ + " INTEGER DEFAULT 0)";
+
private static final String SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY =
"CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
+ RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
@@ -101,13 +114,26 @@
"DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
RecoverableKeyStoreDbHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ super(context, DATABASE_NAME, null, getDbVersion(context));
+ }
+
+ RecoverableKeyStoreDbHelper(Context context, int version) {
+ super(context, DATABASE_NAME, null, version);
+ }
+
+ private static int getDbVersion(Context context) {
+ // TODO(b/254335492): Check flag
+ return DATABASE_VERSION;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_KEYS_ENTRY);
- db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
+ if (db.getVersion() == 6) {
+ db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
+ } else {
+ db.execSQL(SQL_CREATE_USER_METADATA_ENTRY_FOR_V7);
+ }
db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
}
@@ -147,6 +173,11 @@
oldVersion = 6;
}
+ if (oldVersion < 7 && newVersion >= 7) {
+ upgradeDbForVersion7(db);
+ oldVersion = 7;
+ }
+
if (oldVersion != newVersion) {
Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
}
@@ -194,6 +225,14 @@
/*defaultStr=*/ null);
}
+ private void upgradeDbForVersion7(SQLiteDatabase db) {
+ Log.d(TAG, "Updating recoverable keystore database to version 7");
+ addColumnToTable(db, UserMetadataEntry.TABLE_NAME,
+ UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER,
+ "INTEGER DEFAULT 0",
+ /*defaultStr=*/ null);
+ }
+
private static void addColumnToTable(
SQLiteDatabase db, String tableName, String column, String columnType,
String defaultStr) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorage.java
new file mode 100644
index 0000000..b94548b
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorage.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.storage;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.locksettings.recoverablekeystore.SecureBox;
+
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+/**
+ * Memory based storage for keyPair used to send encrypted credentials from a remote device.
+ *
+ * @hide
+ */
+public class RemoteLockscreenValidationSessionStorage {
+
+ private static final long SESSION_TIMEOUT_MILLIS = 10L * DateUtils.MINUTE_IN_MILLIS;
+ private static final String TAG = "RemoteLockscreenValidation";
+
+ @VisibleForTesting
+ final SparseArray<LockscreenVerificationSession> mSessionsByUserId =
+ new SparseArray<>(0);
+
+ /**
+ * Returns session for given user or null.
+ *
+ * @param userId The user id
+ * @return The session info.
+ *
+ * @hide
+ */
+ @Nullable
+ public LockscreenVerificationSession get(int userId) {
+ synchronized (mSessionsByUserId) {
+ return mSessionsByUserId.get(userId);
+ }
+ }
+
+ /**
+ * Creates a new session to verify credentials guess.
+ *
+ * Session will be automatically removed after 10 minutes of inactivity.
+ * @param userId The user id
+ *
+ * @hide
+ */
+ public LockscreenVerificationSession startSession(int userId) {
+ synchronized (mSessionsByUserId) {
+ if (mSessionsByUserId.get(userId) != null) {
+ mSessionsByUserId.delete(userId);
+ }
+
+ KeyPair newKeyPair;
+ try {
+ newKeyPair = SecureBox.genKeyPair();
+ } catch (NoSuchAlgorithmException e) {
+ // impossible
+ throw new RuntimeException(e);
+ }
+ LockscreenVerificationSession newSession =
+ new LockscreenVerificationSession(newKeyPair, SystemClock.elapsedRealtime());
+ mSessionsByUserId.put(userId, newSession);
+ return newSession;
+ }
+ }
+
+ /**
+ * Deletes session for a user.
+ */
+ public void finishSession(int userId) {
+ synchronized (mSessionsByUserId) {
+ mSessionsByUserId.delete(userId);
+ }
+ }
+
+ /**
+ * Creates a task which deletes expired sessions.
+ */
+ public Runnable getLockscreenValidationCleanupTask() {
+ return new LockscreenValidationCleanupTask();
+ }
+
+ /**
+ * Holder for KeyPair used by remote lock screen validation.
+ *
+ * @hide
+ */
+ public class LockscreenVerificationSession {
+ private final KeyPair mKeyPair;
+ private final long mElapsedStartTime;
+
+ /**
+ * @hide
+ */
+ LockscreenVerificationSession(KeyPair keyPair, long elapsedStartTime) {
+ mKeyPair = keyPair;
+ mElapsedStartTime = elapsedStartTime;
+ }
+
+ /**
+ * Returns SecureBox key pair.
+ */
+ public KeyPair getKeyPair() {
+ return mKeyPair;
+ }
+
+ /**
+ * Time when the session started.
+ */
+ private long getElapsedStartTimeMillis() {
+ return mElapsedStartTime;
+ }
+ }
+
+ private class LockscreenValidationCleanupTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ synchronized (mSessionsByUserId) {
+ ArrayList<Integer> keysToRemove = new ArrayList<>();
+ for (int i = 0; i < mSessionsByUserId.size(); i++) {
+ long now = SystemClock.elapsedRealtime();
+ long startTime = mSessionsByUserId.valueAt(i).getElapsedStartTimeMillis();
+ if (now - startTime > SESSION_TIMEOUT_MILLIS) {
+ int userId = mSessionsByUserId.keyAt(i);
+ keysToRemove.add(userId);
+ }
+ }
+ for (Integer userId : keysToRemove) {
+ mSessionsByUserId.delete(userId);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unexpected exception thrown during LockscreenValidationCleanupTask", e);
+ }
+ }
+
+ }
+
+}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 3ad0e44..a9b9b54 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -69,6 +69,7 @@
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -247,6 +248,24 @@
// Binder call
@Override
+ public void showMediaOutputSwitcher(String packageName) {
+ if (!validatePackageName(Binder.getCallingUid(), packageName)) {
+ throw new SecurityException("packageName must match the calling identity");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ StatusBarManagerInternal statusBar =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ statusBar.showMediaOutputSwitcher(packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
public MediaRouterClientState getState(IMediaRouterClient client) {
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 3df46a2..a7e0af3 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -774,6 +774,21 @@
if (!deleteAllUsers) {
returnCode = deletePackageX(internalPackageName, versionCode,
userId, deleteFlags, false /*removedBySystem*/);
+
+ // Get a list of child user profiles and delete if package is
+ // present in clone profile.
+ int[] childUserIds = mUserManagerInternal.getProfileIds(userId, true);
+ for (int childId : childUserIds) {
+ if (childId != userId) {
+ UserInfo userInfo = mUserManagerInternal.getUserInfo(childId);
+ if (userInfo != null && userInfo.isCloneProfile()) {
+ returnCode = deletePackageX(internalPackageName, versionCode,
+ childId, deleteFlags, false /*removedBySystem*/);
+ break;
+ }
+ }
+ }
+
} else {
int[] blockUninstallUserIds = getBlockUninstallForUsers(innerSnapshot,
internalPackageName, users);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ad8e35d..b919330 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1152,8 +1152,8 @@
throw new IOException("Root has not present");
}
return ApkChecksums.verityHashForFile(new File(filename), hashInfo.rawRootHash);
- } catch (IOException ignore) {
- Slog.e(TAG, "ERROR: could not load root hash from incremental install");
+ } catch (IOException e) {
+ Slog.i(TAG, "Could not obtain verity root hash", e);
}
return null;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 1787116..3c5f309 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -27,6 +27,8 @@
import android.os.UserManager;
import android.util.DebugUtils;
+import com.android.internal.annotations.Keep;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
@@ -47,9 +49,10 @@
public @interface OwnerType {
}
- public static final int USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE = 1;
- public static final int USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE = 2;
- public static final int USER_ASSIGNMENT_RESULT_FAILURE = -1;
+ // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
+ @Keep public static final int USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE = 1;
+ @Keep public static final int USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE = 2;
+ @Keep public static final int USER_ASSIGNMENT_RESULT_FAILURE = -1;
private static final String PREFIX_USER_ASSIGNMENT_RESULT = "USER_ASSIGNMENT_RESULT_";
@IntDef(flag = false, prefix = {PREFIX_USER_ASSIGNMENT_RESULT}, value = {
@@ -59,9 +62,10 @@
})
public @interface UserAssignmentResult {}
- public static final int USER_START_MODE_FOREGROUND = 1;
- public static final int USER_START_MODE_BACKGROUND = 2;
- public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
+ // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
+ @Keep public static final int USER_START_MODE_FOREGROUND = 1;
+ @Keep public static final int USER_START_MODE_BACKGROUND = 2;
+ @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
@IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3340e12..762d1f6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -262,7 +262,7 @@
// We need to keep process uid within Integer.MAX_VALUE.
@VisibleForTesting
- static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+ static final int MAX_USER_ID = UserHandle.MAX_SECONDARY_USER_ID;
// Max size of the queue of recently removed users
@VisibleForTesting
@@ -1779,28 +1779,6 @@
}
@Override
- public boolean isMediaSharedWithParent(@UserIdInt int userId) {
- checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
- "isMediaSharedWithParent");
- synchronized (mUsersLock) {
- UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
- return userTypeDetails != null ? userTypeDetails.isProfile()
- && userTypeDetails.isMediaSharedWithParent() : false;
- }
- }
-
- @Override
- public boolean isCredentialSharableWithParent(@UserIdInt int userId) {
- checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
- "isCredentialSharableWithParent");
- synchronized (mUsersLock) {
- UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
- return userTypeDetails != null && userTypeDetails.isProfile()
- && userTypeDetails.isCredentialSharableWithParent();
- }
- }
-
- @Override
public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) {
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
"isUserUnlockingOrUnlocked");
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index ddf3692..f86ee90 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -151,20 +151,6 @@
private final @Nullable int[] mDarkThemeBadgeColors;
/**
- * Denotes if the user shares media with its parent user.
- *
- * <p> Default value is false
- */
- private final boolean mIsMediaSharedWithParent;
-
- /**
- * Denotes if the user shares encryption credentials with its parent user.
- *
- * <p> Default value is false
- */
- private final boolean mIsCredentialSharableWithParent;
-
- /**
* The default {@link UserProperties} for the user type.
* <p> The uninitialized value of each property is implied by {@link UserProperties.Builder}.
*/
@@ -180,8 +166,6 @@
@Nullable Bundle defaultSystemSettings,
@Nullable Bundle defaultSecureSettings,
@Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
- boolean isMediaSharedWithParent,
- boolean isCredentialSharableWithParent,
@NonNull UserProperties defaultUserProperties) {
this.mName = name;
this.mEnabled = enabled;
@@ -201,8 +185,6 @@
this.mBadgeLabels = badgeLabels;
this.mBadgeColors = badgeColors;
this.mDarkThemeBadgeColors = darkThemeBadgeColors;
- this.mIsMediaSharedWithParent = isMediaSharedWithParent;
- this.mIsCredentialSharableWithParent = isCredentialSharableWithParent;
this.mDefaultUserProperties = defaultUserProperties;
}
@@ -309,21 +291,6 @@
return mDarkThemeBadgeColors[Math.min(badgeIndex, mDarkThemeBadgeColors.length - 1)];
}
- /**
- * Returns true if the user has shared media with parent user or false otherwise.
- */
- public boolean isMediaSharedWithParent() {
- return mIsMediaSharedWithParent;
- }
-
- /**
- * Returns true if the user has shared encryption credential with parent user or
- * false otherwise.
- */
- public boolean isCredentialSharableWithParent() {
- return mIsCredentialSharableWithParent;
- }
-
/**
* Returns the reference to the default {@link UserProperties} for this type of user.
@@ -437,8 +404,6 @@
private @DrawableRes int mIconBadge = Resources.ID_NULL;
private @DrawableRes int mBadgePlain = Resources.ID_NULL;
private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
- private boolean mIsMediaSharedWithParent = false;
- private boolean mIsCredentialSharableWithParent = false;
// Default UserProperties cannot be null but for efficiency we don't initialize it now.
// If it isn't set explicitly, {@link UserProperties.Builder#build()} will be used.
private @Nullable UserProperties mDefaultUserProperties = null;
@@ -533,24 +498,6 @@
}
/**
- * Sets shared media property for the user.
- * @param isMediaSharedWithParent the value to be set, true or false
- */
- public Builder setIsMediaSharedWithParent(boolean isMediaSharedWithParent) {
- mIsMediaSharedWithParent = isMediaSharedWithParent;
- return this;
- }
-
- /**
- * Sets shared media property for the user.
- * @param isCredentialSharableWithParent the value to be set, true or false
- */
- public Builder setIsCredentialSharableWithParent(boolean isCredentialSharableWithParent) {
- mIsCredentialSharableWithParent = isCredentialSharableWithParent;
- return this;
- }
-
- /**
* Sets (replacing if necessary) the default UserProperties object for this user type.
* Takes a builder, rather than a built object, to efficiently ensure that a fresh copy of
* properties is stored (since it later might be modified by UserProperties#updateFromXml).
@@ -609,8 +556,6 @@
mDefaultSystemSettings,
mDefaultSecureSettings,
mDefaultCrossProfileIntentFilters,
- mIsMediaSharedWithParent,
- mIsCredentialSharableWithParent,
getDefaultUserProperties());
}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index edb2a4be3b..b8c57b8 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -122,8 +122,6 @@
.setMaxAllowedPerParent(1)
.setLabel(0)
.setDefaultRestrictions(null)
- .setIsMediaSharedWithParent(true)
- .setIsCredentialSharableWithParent(true)
.setDefaultCrossProfileIntentFilters(getDefaultCloneCrossProfileIntentFilter())
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
@@ -135,7 +133,10 @@
.setCrossProfileIntentFilterAccessControl(
UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
.setCrossProfileIntentResolutionStrategy(UserProperties
- .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING));
+ .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING)
+ .setMediaSharedWithParent(true)
+ .setCredentialShareableWithParent(true)
+ );
}
/**
@@ -167,11 +168,11 @@
.setDefaultRestrictions(getDefaultManagedProfileRestrictions())
.setDefaultSecureSettings(getDefaultManagedProfileSecureSettings())
.setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter())
- .setIsCredentialSharableWithParent(true)
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
- .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE));
+ .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
+ .setCredentialShareableWithParent(true));
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 60751e6..4e9cd2e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -664,7 +664,7 @@
dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
break;
case MSG_DISPATCH_SHOW_RECENTS:
- showRecents();
+ showRecentApps(false);
break;
case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
showGlobalActionsInternal();
@@ -991,14 +991,7 @@
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (count > 3 && count <= getMaxMultiPressPowerCount()) {
Slog.d(TAG, "No behavior defined for power press count " + count);
- } else if (count == 1 && interactive) {
- if (beganFromNonInteractive) {
- // The "screen is off" case, where we might want to start dreaming on power button
- // press.
- attemptToDreamFromShortPowerButtonPress(false, () -> {});
- return;
- }
-
+ } else if (count == 1 && interactive && !beganFromNonInteractive) {
if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) {
Slog.i(TAG, "Suppressing power key because the user is interacting with the "
+ "fingerprint sensor");
@@ -2927,7 +2920,7 @@
break;
case KeyEvent.KEYCODE_RECENT_APPS:
if (down && repeatCount == 0) {
- showRecents();
+ showRecentApps(false /* triggeredFromAltTab */);
}
return key_consumed;
case KeyEvent.KEYCODE_APP_SWITCH:
@@ -3110,23 +3103,22 @@
}
break;
case KeyEvent.KEYCODE_TAB:
- if (down) {
- if (event.isMetaPressed()) {
- if (!keyguardOn && isUserSetupComplete()) {
- showRecents();
+ if (down && event.isMetaPressed()) {
+ if (!keyguardOn && isUserSetupComplete()) {
+ showRecentApps(false);
+ return key_consumed;
+ }
+ } else if (down && repeatCount == 0) {
+ // Display task switcher for ALT-TAB.
+ if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
+ final int shiftlessModifiers =
+ event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+ if (KeyEvent.metaStateHasModifiers(
+ shiftlessModifiers, KeyEvent.META_ALT_ON)) {
+ mRecentAppsHeldModifiers = shiftlessModifiers;
+ showRecentApps(true);
return key_consumed;
}
- } else {
- // Display task switcher for ALT-TAB.
- if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
- final int modifiers = event.getModifiers();
- if (KeyEvent.metaStateHasModifiers(modifiers, KeyEvent.META_ALT_ON)) {
- mRecentAppsHeldModifiers = modifiers;
- showRecentsFromAltTab(KeyEvent.metaStateHasModifiers(modifiers,
- KeyEvent.META_SHIFT_ON));
- return key_consumed;
- }
- }
}
}
break;
@@ -3662,19 +3654,11 @@
mHandler.obtainMessage(MSG_DISPATCH_SHOW_RECENTS).sendToTarget();
}
- private void showRecents() {
+ private void showRecentApps(boolean triggeredFromAltTab) {
mPreloadedRecentApps = false; // preloading no longer needs to be canceled
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.showRecentApps(false /* triggeredFromAltTab */, false /* forward */);
- }
- }
-
- private void showRecentsFromAltTab(boolean forward) {
- mPreloadedRecentApps = false; // preloading no longer needs to be canceled
- StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
- if (statusbar != null) {
- statusbar.showRecentApps(true /* triggeredFromAltTab */, forward);
+ statusbar.showRecentApps(triggeredFromAltTab);
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 94fb840..ca5fa5f 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -67,6 +67,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -91,6 +92,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
/**
* This interface supplies all UI-specific behavior of the window manager. An
@@ -357,6 +359,11 @@
* windows even if the rotation hasn't changed.
*/
void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout);
+
+ /**
+ * Invoked when a screenshot is taken of the given display to notify registered listeners.
+ */
+ List<ComponentName> notifyScreenshotListeners(int displayId);
}
/**
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index fd64c75..7beb1ed 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -36,12 +36,14 @@
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.server.PackageWatchdog;
import com.android.server.PackageWatchdog.FailureReasons;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
+import com.android.server.SystemConfig;
import com.android.server.pm.ApexManager;
import java.io.BufferedReader;
@@ -358,6 +360,13 @@
private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
@FailureReasons int rollbackReason) {
assertInWorkerThread();
+
+ if (isAutomaticRollbackDenied(SystemConfig.getInstance(), failedPackage)) {
+ Slog.d(TAG, "Automatic rollback not allowed for package "
+ + failedPackage.getPackageName());
+ return;
+ }
+
final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
final String failedPackageToLog;
@@ -420,6 +429,17 @@
}
/**
+ * Returns true if this package is not eligible for automatic rollback.
+ */
+ @VisibleForTesting
+ @AnyThread
+ public static boolean isAutomaticRollbackDenied(SystemConfig systemConfig,
+ VersionedPackage versionedPackage) {
+ return systemConfig.getAutomaticRollbackDenylistedPackages()
+ .contains(versionedPackage.getPackageName());
+ }
+
+ /**
* Two-phase rollback:
* 1. roll back rebootless apexes first
* 2. roll back all remaining rollbacks if native crash doesn't stop after (1) is done
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index f973f5c..8068c6f 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -249,7 +249,7 @@
targetDir.mkdirs();
File targetFile = new File(targetDir, sourceFile.getName());
- boolean fallbackToCopy = !isLinkPossible(sourceFile, targetFile);
+ boolean fallbackToCopy = !isLinkPossible(sourceFile, targetDir);
if (!fallbackToCopy) {
try {
// Create a hard link to avoid copy
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/OWNERS b/services/core/java/com/android/server/soundtrigger_middleware/OWNERS
deleted file mode 100644
index e5d0370..0000000
--- a/services/core/java/com/android/server/soundtrigger_middleware/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-ytai@google.com
-elaurent@google.com
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index 411b2fa..e148a48 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -72,8 +72,7 @@
new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName),
Context.BIND_AUTO_CREATE
| Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_INCLUDE_CAPABILITIES
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
+ | Context.BIND_INCLUDE_CAPABILITIES,
userId,
IRecognitionService.Stub::asInterface);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 05b3ce7..5521384 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -39,7 +39,7 @@
void cancelPreloadRecentApps();
- void showRecentApps(boolean triggeredFromAltTab, boolean forward);
+ void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 0f49981..83f4805 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -454,10 +454,10 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
if (mBar != null) {
try {
- mBar.showRecentApps(triggeredFromAltTab, forward);
+ mBar.showRecentApps(triggeredFromAltTab);
} catch (RemoteException ex) {}
}
}
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
index fef7148..ce1d525 100644
--- a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -263,11 +263,11 @@
long gnssUnixEpochTimeMillis = locationTime.getUnixEpochTimeMillis();
long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
- UnixEpochTime timeSignal = new UnixEpochTime(elapsedRealtimeMs, gnssUnixEpochTimeMillis);
- mLastSuggestedGnssTime = timeSignal;
+ UnixEpochTime unixEpochTime = new UnixEpochTime(elapsedRealtimeMs, gnssUnixEpochTimeMillis);
+ mLastSuggestedGnssTime = unixEpochTime;
- GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
- mTimeDetectorInternal.suggestGnssTime(timeSuggestion);
+ GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime);
+ mTimeDetectorInternal.suggestGnssTime(suggestion);
}
@Override
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
index 24533d7..5df5cbc 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
@@ -56,11 +56,19 @@
* valid but does not change the time because it matches the current device time is considered
* accepted.
*/
- boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion manualTimeSuggestion);
+ boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion suggestion);
- /** Used to pass new network time suggestions to the time detector. */
- void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal);
+ /**
+ * Suggests a network time to the time detector. The suggestion may not be used by the time
+ * detector to set the device's time depending on device configuration and user settings, but
+ * can replace previous network suggestions received.
+ */
+ void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
- /** Used to pass new GNSS time suggestions to the time detector. */
- void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal);
-}
\ No newline at end of file
+ /**
+ * Suggests a GNSS-derived time to the time detector. The suggestion may not be used by the time
+ * detector to set the device's time depending on device configuration and user settings, but
+ * can replace previous GNSS suggestions received.
+ */
+ void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion);
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
index 9839de0..af168f8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
@@ -72,24 +72,24 @@
}
@Override
- public boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion timeSignal) {
- Objects.requireNonNull(timeSignal);
+ public boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion suggestion) {
+ Objects.requireNonNull(suggestion);
int userId = mCurrentUserIdentityInjector.getCurrentUserId();
- return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal, false);
+ return mTimeDetectorStrategy.suggestManualTime(userId, suggestion, false);
}
@Override
- public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
- Objects.requireNonNull(timeSignal);
+ public void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
+ Objects.requireNonNull(suggestion);
- mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
+ mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion));
}
@Override
- public void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
- Objects.requireNonNull(timeSignal);
+ public void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion) {
+ Objects.requireNonNull(suggestion);
- mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(timeSignal));
+ mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(suggestion));
}
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 3e23953..a9dcff4 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -319,9 +319,9 @@
}
@Override
- public boolean setManualTime(@NonNull ManualTimeSuggestion timeSignal) {
+ public boolean setManualTime(@NonNull ManualTimeSuggestion suggestion) {
enforceManageTimeDetectorPermission();
- Objects.requireNonNull(timeSignal);
+ Objects.requireNonNull(suggestion);
// This calls suggestManualTime() as the logic is identical, it only differs in the
// permission required, which is handled on the line above.
@@ -330,7 +330,7 @@
try {
final boolean bypassUserPolicyChecks = false;
return mTimeDetectorStrategy.suggestManualTime(
- userId, timeSignal, bypassUserPolicyChecks);
+ userId, suggestion, bypassUserPolicyChecks);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -363,11 +363,11 @@
/**
* Suggests network time with permission checks. For use by {@link TimeDetectorShellCommand}.
*/
- void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
+ void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
enforceSuggestNetworkTimePermission();
- Objects.requireNonNull(timeSignal);
+ Objects.requireNonNull(suggestion);
- mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
+ mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion));
}
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 9dca6ec..dbd7172 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -87,7 +87,7 @@
boolean confirmTime(@NonNull UnixEpochTime confirmationTime);
/** Processes the suggested time from telephony sources. */
- void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
+ void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion);
/**
* Processes the suggested manually entered time. Returns {@code false} if the suggestion was
@@ -98,11 +98,15 @@
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
- boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion timeSuggestion,
+ boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion,
boolean bypassUserPolicyChecks);
- /** Processes the suggested time from network sources. */
- void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
+ /**
+ * Processes the suggested network time. The suggestion may not be used to set the device's time
+ * depending on device configuration and user settings, but can replace previous network
+ * suggestions received.
+ */
+ void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
/**
* Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
@@ -119,10 +123,10 @@
void clearLatestNetworkSuggestion();
/** Processes the suggested time from gnss sources. */
- void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion);
+ void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion);
/** Processes the suggested time from external sources. */
- void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion);
+ void suggestExternalTime(@NonNull ExternalTimeSuggestion suggestion);
// Utility methods below are to be moved to a better home when one becomes more obvious.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 09bb803..d679bbe 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -208,7 +208,7 @@
if (DBG) {
Slog.d(LOG_TAG, "External suggestion received."
+ " currentUserConfig=" + currentUserConfig
- + " newSuggestion=" + suggestion);
+ + " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -230,7 +230,7 @@
if (DBG) {
Slog.d(LOG_TAG, "GNSS suggestion received."
+ " currentUserConfig=" + currentUserConfig
- + " newSuggestion=" + suggestion);
+ + " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -289,7 +289,7 @@
if (DBG) {
Slog.d(LOG_TAG, "Network suggestion received."
+ " currentUserConfig=" + currentUserConfig
- + " newSuggestion=" + suggestion);
+ + " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -311,7 +311,7 @@
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
- String reason = "New network time suggested. timeSuggestion=" + suggestion;
+ String reason = "New network time suggested. suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@@ -396,29 +396,29 @@
}
@Override
- public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion) {
+ public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion) {
// Empty time suggestion means that telephony network connectivity has been lost.
// The passage of time is relentless, and we don't expect our users to use a time machine,
// so we can continue relying on previous suggestions when we lose connectivity. This is
// unlike time zone, where a user may lose connectivity when boarding a flight and where we
// do want to "forget" old signals. Suggestions that are too old are discarded later in the
// detection algorithm.
- if (timeSuggestion.getUnixEpochTime() == null) {
+ if (suggestion.getUnixEpochTime() == null) {
return;
}
- if (!validateAutoSuggestionTime(timeSuggestion.getUnixEpochTime(), timeSuggestion)) {
+ if (!validateAutoSuggestionTime(suggestion.getUnixEpochTime(), suggestion)) {
return;
}
// Perform input filtering and record the validated suggestion against the slotIndex.
- if (!storeTelephonySuggestion(timeSuggestion)) {
+ if (!storeTelephonySuggestion(suggestion)) {
return;
}
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
- String reason = "New telephony time suggested. timeSuggestion=" + timeSuggestion;
+ String reason = "New telephony time suggested. suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@@ -623,19 +623,19 @@
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_GNSS) {
- GnssTimeSuggestion gnssTimeSuggestion = findLatestValidGnssSuggestion();
- if (gnssTimeSuggestion != null) {
- newUnixEpochTime = gnssTimeSuggestion.getUnixEpochTime();
+ GnssTimeSuggestion gnssSuggestion = findLatestValidGnssSuggestion();
+ if (gnssSuggestion != null) {
+ newUnixEpochTime = gnssSuggestion.getUnixEpochTime();
cause = "Found good gnss suggestion."
- + ", gnssTimeSuggestion=" + gnssTimeSuggestion
+ + ", gnssSuggestion=" + gnssSuggestion
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_EXTERNAL) {
- ExternalTimeSuggestion externalTimeSuggestion = findLatestValidExternalSuggestion();
- if (externalTimeSuggestion != null) {
- newUnixEpochTime = externalTimeSuggestion.getUnixEpochTime();
+ ExternalTimeSuggestion externalSuggestion = findLatestValidExternalSuggestion();
+ if (externalSuggestion != null) {
+ newUnixEpochTime = externalSuggestion.getUnixEpochTime();
cause = "Found good external suggestion."
- + ", externalTimeSuggestion=" + externalTimeSuggestion
+ + ", externalSuggestion=" + externalSuggestion
+ ", detectionReason=" + detectionReason;
}
} else {
@@ -742,14 +742,14 @@
private static int scoreTelephonySuggestion(
@ElapsedRealtimeLong long elapsedRealtimeMillis,
- @NonNull TelephonyTimeSuggestion timeSuggestion) {
+ @NonNull TelephonyTimeSuggestion suggestion) {
// Validate first.
- UnixEpochTime unixEpochTime = timeSuggestion.getUnixEpochTime();
+ UnixEpochTime unixEpochTime = suggestion.getUnixEpochTime();
if (!validateSuggestionUnixEpochTime(elapsedRealtimeMillis, unixEpochTime)) {
Slog.w(LOG_TAG, "Existing suggestion found to be invalid"
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + ", timeSuggestion=" + timeSuggestion);
+ + ", suggestion=" + suggestion);
return TELEPHONY_INVALID_SCORE;
}
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index 5cb48c2..449b41a 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -18,6 +18,7 @@
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
+import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -27,6 +28,7 @@
import com.android.server.SystemTimeZone.TimeZoneConfidence;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
@@ -35,7 +37,10 @@
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
- EnvironmentImpl() {
+ @NonNull private final Handler mHandler;
+
+ EnvironmentImpl(@NonNull Handler handler) {
+ mHandler = Objects.requireNonNull(handler);
}
@Override
@@ -72,4 +77,9 @@
public void dumpDebugLog(@NonNull PrintWriter printWriter) {
SystemTimeZone.dump(printWriter);
}
+
+ @Override
+ public void runAsync(@NonNull Runnable runnable) {
+ mHandler.post(runnable);
+ }
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index 74a518b..6c0ce0c 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -56,7 +56,7 @@
* valid but does not change the time zone because it matches the current device time zone is
* considered accepted.
*/
- boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion);
+ boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion suggestion);
/**
* Handles the supplied {@link LocationAlgorithmEvent}. The detector may ignore the event based
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 07d0473..fad27f5 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -66,13 +66,13 @@
}
@Override
- public boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
- Objects.requireNonNull(timeZoneSuggestion);
+ public boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion suggestion) {
+ Objects.requireNonNull(suggestion);
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyChecks = true;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
- currentUserId, timeZoneSuggestion, bypassUserPolicyChecks);
+ currentUserId, suggestion, bypassUserPolicyChecks);
}
@Override
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 10cd5d1..dac4bf8 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -346,7 +346,7 @@
}
@Override
- public boolean setManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+ public boolean setManualTimeZone(@NonNull ManualTimeZoneSuggestion suggestion) {
enforceManageTimeZoneDetectorPermission();
// This calls suggestManualTimeZone() as the logic is identical, it only differs in the
@@ -356,34 +356,34 @@
try {
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
- userId, timeZoneSuggestion, bypassUserPolicyChecks);
+ userId, suggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@Override
- public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+ public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion suggestion) {
enforceSuggestManualTimeZonePermission();
- Objects.requireNonNull(timeZoneSuggestion);
+ Objects.requireNonNull(suggestion);
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
- userId, timeZoneSuggestion, bypassUserPolicyChecks);
+ userId, suggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@Override
- public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
+ public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion) {
enforceSuggestTelephonyTimeZonePermission();
- Objects.requireNonNull(timeZoneSuggestion);
+ Objects.requireNonNull(suggestion);
- mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion));
+ mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(suggestion));
}
boolean isTelephonyTimeZoneDetectionSupported() {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index e0e3565..dddb46f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -102,6 +102,11 @@
* Dumps the time zone debug log to the supplied {@link PrintWriter}.
*/
void dumpDebugLog(PrintWriter printWriter);
+
+ /**
+ * Requests that the supplied runnable be invoked asynchronously.
+ */
+ void runAsync(@NonNull Runnable runnable);
}
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
@@ -200,10 +205,6 @@
@NonNull
private final ServiceConfigAccessor mServiceConfigAccessor;
- /** The handler used for asynchronous operations triggered by this. */
- @NonNull
- private final Handler mStateChangeHandler;
-
@GuardedBy("this")
@NonNull private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>();
@@ -246,17 +247,16 @@
public static TimeZoneDetectorStrategyImpl create(
@NonNull Handler handler, @NonNull ServiceConfigAccessor serviceConfigAccessor) {
- Environment environment = new EnvironmentImpl();
- return new TimeZoneDetectorStrategyImpl(serviceConfigAccessor, handler, environment);
+ Environment environment = new EnvironmentImpl(handler);
+ return new TimeZoneDetectorStrategyImpl(serviceConfigAccessor, environment);
}
@VisibleForTesting
public TimeZoneDetectorStrategyImpl(
@NonNull ServiceConfigAccessor serviceConfigAccessor,
- @NonNull Handler handler, @NonNull Environment environment) {
+ @NonNull Environment environment) {
mEnvironment = Objects.requireNonNull(environment);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
- mStateChangeHandler = Objects.requireNonNull(handler);
// Start with telephony fallback enabled.
mTelephonyTimeZoneFallbackEnabled =
@@ -349,7 +349,7 @@
private void notifyStateChangeListenersAsynchronously() {
for (StateChangeListener listener : mStateChangeListeners) {
// This is queuing asynchronous notification, so no need to surrender the "this" lock.
- mStateChangeHandler.post(listener::onChange);
+ mEnvironment.runAsync(listener::onChange);
}
}
@@ -479,7 +479,7 @@
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
if (DBG) {
Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
- + " newSuggestion=" + suggestion);
+ + " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 73b2238..29b37ce 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2184,10 +2184,10 @@
return null;
}
- final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "acquireTvInputHardware");
+ final long identity = Binder.clearCallingIdentity();
try {
return mTvInputHardwareManager.acquireHardware(
deviceId, callback, info, callingUid, resolvedUserId,
@@ -2205,10 +2205,10 @@
return;
}
- final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "releaseTvInputHardware");
+ final long identity = Binder.clearCallingIdentity();
try {
mTvInputHardwareManager.releaseHardware(
deviceId, hardware, callingUid, resolvedUserId);
@@ -2350,10 +2350,10 @@
throws RemoteException {
ensureCaptureTvInputPermission();
- final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "getAvailableTvStreamConfigList");
+ final long identity = Binder.clearCallingIdentity();
try {
return mTvInputHardwareManager.getAvailableTvStreamConfigList(
inputId, callingUid, resolvedUserId);
@@ -2368,10 +2368,10 @@
throws RemoteException {
ensureCaptureTvInputPermission();
- final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "captureFrame");
+ final long identity = Binder.clearCallingIdentity();
try {
String hardwareInputId = null;
synchronized (mLock) {
@@ -2400,10 +2400,10 @@
@Override
public boolean isSingleSessionActive(int userId) throws RemoteException {
ensureCaptureTvInputPermission();
- final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "isSingleSessionActive");
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index ca4a32f..099c9ae 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -16,9 +16,6 @@
package com.android.server.vcn;
-import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
-import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
@@ -48,7 +45,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.vcn.util.PersistableBundleUtils;
import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import java.util.ArrayList;
@@ -109,6 +105,12 @@
@NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
+ @NonNull
+ private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
+ (int logicalSlotIndex, int subscriptionId, int carrierId, int specificCarrierId) ->
+ handleActionCarrierConfigChanged(logicalSlotIndex, subscriptionId);
+
+
public TelephonySubscriptionTracker(
@NonNull Context context,
@NonNull Handler handler,
@@ -149,13 +151,14 @@
public void register() {
final HandlerExecutor executor = new HandlerExecutor(mHandler);
final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
mContext.registerReceiver(this, filter, null, mHandler);
mSubscriptionManager.addOnSubscriptionsChangedListener(
executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
+ mCarrierConfigManager.registerCarrierConfigChangeListener(executor,
+ mCarrierConfigChangeListener);
registerCarrierPrivilegesCallbacks();
}
@@ -197,6 +200,7 @@
mContext.unregisterReceiver(this);
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
+ mCarrierConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener);
unregisterCarrierPrivilegesCallbacks();
}
@@ -273,7 +277,7 @@
}
/**
- * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED
+ * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED
*
* <p>The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all
* serialized on mHandler, avoiding the need for locking.
@@ -281,9 +285,6 @@
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
- case ACTION_CARRIER_CONFIG_CHANGED:
- handleActionCarrierConfigChanged(context, intent);
- break;
case ACTION_MULTI_SIM_CONFIG_CHANGED:
handleActionMultiSimConfigChanged(context, intent);
break;
@@ -310,26 +311,21 @@
handleSubscriptionsChanged();
}
- private void handleActionCarrierConfigChanged(Context context, Intent intent) {
- // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it
- // already was for an identified carrier, we can stop waiting for initial load to complete
- final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID);
- final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX);
-
+ private void handleActionCarrierConfigChanged(int slotId, int subId) {
if (slotId == INVALID_SIM_SLOT_INDEX) {
return;
}
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
+ // Get only configs as needed to save memory.
+ final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId,
+ VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
mReadySubIdsBySlotId.put(slotId, subId);
- final PersistableBundle minimized =
- PersistableBundleUtils.minimizeBundle(
- carrierConfig, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
- if (minimized != null) {
- mSubIdToCarrierConfigMap.put(subId, new PersistableBundleWrapper(minimized));
+ if (!carrierConfig.isEmpty()) {
+ mSubIdToCarrierConfigMap.put(subId,
+ new PersistableBundleWrapper(carrierConfig));
}
handleSubscriptionsChanged();
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
new file mode 100644
index 0000000..49b125c
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpaper;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.server.wallpaper.WallpaperUtils.RECORD_FILE;
+import static com.android.server.wallpaper.WallpaperUtils.RECORD_LOCK_FILE;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
+import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageDecoder;
+import android.graphics.Rect;
+import android.os.FileUtils;
+import android.os.SELinux;
+import android.util.Slog;
+import android.view.DisplayInfo;
+
+import com.android.server.utils.TimingsTraceAndSlog;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+
+/**
+ * Helper file for wallpaper cropping
+ * Meant to have a single instance, only used by the WallpaperManagerService
+ */
+class WallpaperCropper {
+
+ private static final String TAG = WallpaperCropper.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_CROP = true;
+
+ private final WallpaperDisplayHelper mWallpaperDisplayHelper;
+
+ WallpaperCropper(WallpaperDisplayHelper wallpaperDisplayHelper) {
+ mWallpaperDisplayHelper = wallpaperDisplayHelper;
+ }
+
+ /**
+ * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
+ * for display.
+ *
+ * This will generate the crop and write it in the file
+ */
+ void generateCrop(WallpaperData wallpaper) {
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+ t.traceBegin("WPMS.generateCrop");
+ generateCropInternal(wallpaper);
+ t.traceEnd();
+ }
+
+ private void generateCropInternal(WallpaperData wallpaper) {
+ boolean success = false;
+
+ // Only generate crop for default display.
+ final WallpaperDisplayHelper.DisplayData wpData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final Rect cropHint = new Rect(wallpaper.cropHint);
+ final DisplayInfo displayInfo = mWallpaperDisplayHelper.getDisplayInfo(DEFAULT_DISPLAY);
+
+ if (DEBUG) {
+ Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
+ + Integer.toHexString(wallpaper.mWhich)
+ + " to " + wallpaper.cropFile.getName()
+ + " crop=(" + cropHint.width() + 'x' + cropHint.height()
+ + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')');
+ }
+
+ // Analyse the source; needed in multiple cases
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+ if (options.outWidth <= 0 || options.outHeight <= 0) {
+ Slog.w(TAG, "Invalid wallpaper data");
+ success = false;
+ } else {
+ boolean needCrop = false;
+ boolean needScale;
+
+ // Empty crop means use the full image
+ if (cropHint.isEmpty()) {
+ cropHint.left = cropHint.top = 0;
+ cropHint.right = options.outWidth;
+ cropHint.bottom = options.outHeight;
+ } else {
+ // force the crop rect to lie within the measured bounds
+ int dx = cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0;
+ int dy = cropHint.bottom > options.outHeight
+ ? options.outHeight - cropHint.bottom : 0;
+ cropHint.offset(dx, dy);
+
+ // If the crop hint was larger than the image we just overshot. Patch things up.
+ if (cropHint.left < 0) {
+ cropHint.left = 0;
+ }
+ if (cropHint.top < 0) {
+ cropHint.top = 0;
+ }
+
+ // Don't bother cropping if what we're left with is identity
+ needCrop = (options.outHeight > cropHint.height()
+ || options.outWidth > cropHint.width());
+ }
+
+ // scale if the crop height winds up not matching the recommended metrics
+ needScale = cropHint.height() > wpData.mHeight
+ || cropHint.height() > GLHelper.getMaxTextureSize()
+ || cropHint.width() > GLHelper.getMaxTextureSize();
+
+ //make sure screen aspect ratio is preserved if width is scaled under screen size
+ if (needScale) {
+ final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height();
+ final int newWidth = (int) (cropHint.width() * scaleByHeight);
+ if (newWidth < displayInfo.logicalWidth) {
+ final float screenAspectRatio =
+ (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth;
+ cropHint.bottom = (int) (cropHint.width() * screenAspectRatio);
+ needCrop = true;
+ }
+ }
+
+ if (DEBUG_CROP) {
+ Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
+ Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
+ Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
+ Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
+ }
+
+ if (!needCrop && !needScale) {
+ // Simple case: the nominal crop fits what we want, so we take
+ // the whole thing and just copy the image file directly.
+
+ // TODO: It is not accurate to estimate bitmap size without decoding it,
+ // may be we can try to remove this optimized way in the future,
+ // that means, we will always go into the 'else' block.
+
+ success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+
+ if (!success) {
+ wallpaper.cropFile.delete();
+ // TODO: fall back to default wallpaper in this case
+ }
+
+ if (DEBUG) {
+ long estimateSize = (long) options.outWidth * options.outHeight * 4;
+ Slog.v(TAG, "Null crop of new wallpaper, estimate size="
+ + estimateSize + ", success=" + success);
+ }
+ } else {
+ // Fancy case: crop and scale. First, we decode and scale down if appropriate.
+ FileOutputStream f = null;
+ BufferedOutputStream bos = null;
+ try {
+ // This actually downsamples only by powers of two, but that's okay; we do
+ // a proper scaling blit later. This is to minimize transient RAM use.
+ // We calculate the largest power-of-two under the actual ratio rather than
+ // just let the decode take care of it because we also want to remap where the
+ // cropHint rectangle lies in the decoded [super]rect.
+ final int actualScale = cropHint.height() / wpData.mHeight;
+ int scale = 1;
+ while (2 * scale <= actualScale) {
+ scale *= 2;
+ }
+ options.inSampleSize = scale;
+ options.inJustDecodeBounds = false;
+
+ final Rect estimateCrop = new Rect(cropHint);
+ estimateCrop.scale(1f / options.inSampleSize);
+ final float hRatio = (float) wpData.mHeight / estimateCrop.height();
+ final int destHeight = (int) (estimateCrop.height() * hRatio);
+ final int destWidth = (int) (estimateCrop.width() * hRatio);
+
+ // We estimated an invalid crop, try to adjust the cropHint to get a valid one.
+ if (destWidth > GLHelper.getMaxTextureSize()) {
+ int newHeight = (int) (wpData.mHeight / hRatio);
+ int newWidth = (int) (wpData.mWidth / hRatio);
+
+ if (DEBUG) {
+ Slog.v(TAG, "Invalid crop dimensions, trying to adjust.");
+ }
+
+ estimateCrop.set(cropHint);
+ estimateCrop.left += (cropHint.width() - newWidth) / 2;
+ estimateCrop.top += (cropHint.height() - newHeight) / 2;
+ estimateCrop.right = estimateCrop.left + newWidth;
+ estimateCrop.bottom = estimateCrop.top + newHeight;
+ cropHint.set(estimateCrop);
+ estimateCrop.scale(1f / options.inSampleSize);
+ }
+
+ // We've got the safe cropHint; now we want to scale it properly to
+ // the desired rectangle.
+ // That's a height-biased operation: make it fit the hinted height.
+ final int safeHeight = (int) (estimateCrop.height() * hRatio);
+ final int safeWidth = (int) (estimateCrop.width() * hRatio);
+
+ if (DEBUG_CROP) {
+ Slog.v(TAG, "Decode parameters:");
+ Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
+ Slog.v(TAG, " down sampling=" + options.inSampleSize
+ + ", hRatio=" + hRatio);
+ Slog.v(TAG, " dest=" + destWidth + "x" + destHeight);
+ Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight);
+ Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
+ }
+
+ //Create a record file and will delete if ImageDecoder work well.
+ final String recordName =
+ (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
+ ? RECORD_FILE : RECORD_LOCK_FILE);
+ final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
+ record.createNewFile();
+ Slog.v(TAG, "record path =" + record.getPath()
+ + ", record name =" + record.getName());
+
+ final ImageDecoder.Source srcData =
+ ImageDecoder.createSource(wallpaper.wallpaperFile);
+ final int sampleSize = scale;
+ Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
+ decoder.setTargetSampleSize(sampleSize);
+ decoder.setCrop(estimateCrop);
+ });
+
+ record.delete();
+
+ if (cropped == null) {
+ Slog.e(TAG, "Could not decode new wallpaper");
+ } else {
+ // We are safe to create final crop with safe dimensions now.
+ final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
+ safeWidth, safeHeight, true);
+ if (DEBUG) {
+ Slog.v(TAG, "Final extract:");
+ Slog.v(TAG, " dims: w=" + wpData.mWidth
+ + " h=" + wpData.mHeight);
+ Slog.v(TAG, " out: w=" + finalCrop.getWidth()
+ + " h=" + finalCrop.getHeight());
+ }
+
+ f = new FileOutputStream(wallpaper.cropFile);
+ bos = new BufferedOutputStream(f, 32 * 1024);
+ finalCrop.compress(Bitmap.CompressFormat.PNG, 100, bos);
+ // don't rely on the implicit flush-at-close when noting success
+ bos.flush();
+ success = true;
+ }
+ } catch (Exception e) {
+ if (DEBUG) {
+ Slog.e(TAG, "Error decoding crop", e);
+ }
+ } finally {
+ IoUtils.closeQuietly(bos);
+ IoUtils.closeQuietly(f);
+ }
+ }
+ }
+
+ if (!success) {
+ Slog.e(TAG, "Unable to apply new wallpaper");
+ wallpaper.cropFile.delete();
+ }
+
+ if (wallpaper.cropFile.exists()) {
+ boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+ if (DEBUG) {
+ Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
index a380dea..f02ee66 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
@@ -27,7 +27,6 @@
import android.view.Display;
import android.view.DisplayInfo;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.WindowManagerInternal;
import java.util.function.Consumer;
@@ -36,7 +35,6 @@
*/
class WallpaperDisplayHelper {
- @VisibleForTesting
static final class DisplayData {
int mWidth = -1;
int mHeight = -1;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b146767..bf09b67 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -74,7 +74,6 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
-import android.graphics.ImageDecoder;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
@@ -109,7 +108,6 @@
import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.Display;
-import android.view.DisplayInfo;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -132,7 +130,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -308,7 +305,7 @@
}
loadSettingsLocked(wallpaper.userId, true);
}
- generateCrop(wallpaper);
+ mWallpaperCropper.generateCrop(wallpaper);
if (DEBUG) {
Slog.v(TAG, "Crop done; invoking completion callback");
}
@@ -593,233 +590,6 @@
return colors;
}
- /**
- * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
- * for display.
- */
- void generateCrop(WallpaperData wallpaper) {
- TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
- t.traceBegin("WPMS.generateCrop");
- generateCropInternal(wallpaper);
- t.traceEnd();
- }
-
- private void generateCropInternal(WallpaperData wallpaper) {
- boolean success = false;
-
- // Only generate crop for default display.
- final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
- final Rect cropHint = new Rect(wallpaper.cropHint);
- final DisplayInfo displayInfo = mWallpaperDisplayHelper.getDisplayInfo(DEFAULT_DISPLAY);
-
- if (DEBUG) {
- Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
- + Integer.toHexString(wallpaper.mWhich)
- + " to " + wallpaper.cropFile.getName()
- + " crop=(" + cropHint.width() + 'x' + cropHint.height()
- + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')');
- }
-
- // Analyse the source; needed in multiple cases
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
- if (options.outWidth <= 0 || options.outHeight <= 0) {
- Slog.w(TAG, "Invalid wallpaper data");
- success = false;
- } else {
- boolean needCrop = false;
- boolean needScale = false;
-
- // Empty crop means use the full image
- if (cropHint.isEmpty()) {
- cropHint.left = cropHint.top = 0;
- cropHint.right = options.outWidth;
- cropHint.bottom = options.outHeight;
- } else {
- // force the crop rect to lie within the measured bounds
- cropHint.offset(
- (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
- (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
-
- // If the crop hint was larger than the image we just overshot. Patch things up.
- if (cropHint.left < 0) {
- cropHint.left = 0;
- }
- if (cropHint.top < 0) {
- cropHint.top = 0;
- }
-
- // Don't bother cropping if what we're left with is identity
- needCrop = (options.outHeight > cropHint.height()
- || options.outWidth > cropHint.width());
- }
-
- // scale if the crop height winds up not matching the recommended metrics
- needScale = cropHint.height() > wpData.mHeight
- || cropHint.height() > GLHelper.getMaxTextureSize()
- || cropHint.width() > GLHelper.getMaxTextureSize();
-
- //make sure screen aspect ratio is preserved if width is scaled under screen size
- if (needScale) {
- final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height();
- final int newWidth = (int) (cropHint.width() * scaleByHeight);
- if (newWidth < displayInfo.logicalWidth) {
- final float screenAspectRatio =
- (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth;
- cropHint.bottom = (int) (cropHint.width() * screenAspectRatio);
- needCrop = true;
- }
- }
-
- if (DEBUG_CROP) {
- Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
- Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
- Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
- Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
- }
-
- if (!needCrop && !needScale) {
- // Simple case: the nominal crop fits what we want, so we take
- // the whole thing and just copy the image file directly.
-
- // TODO: It is not accurate to estimate bitmap size without decoding it,
- // may be we can try to remove this optimized way in the future,
- // that means, we will always go into the 'else' block.
-
- success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
-
- if (!success) {
- wallpaper.cropFile.delete();
- // TODO: fall back to default wallpaper in this case
- }
-
- if (DEBUG) {
- long estimateSize = (long) options.outWidth * options.outHeight * 4;
- Slog.v(TAG, "Null crop of new wallpaper, estimate size="
- + estimateSize + ", success=" + success);
- }
- } else {
- // Fancy case: crop and scale. First, we decode and scale down if appropriate.
- FileOutputStream f = null;
- BufferedOutputStream bos = null;
- try {
- // This actually downsamples only by powers of two, but that's okay; we do
- // a proper scaling blit later. This is to minimize transient RAM use.
- // We calculate the largest power-of-two under the actual ratio rather than
- // just let the decode take care of it because we also want to remap where the
- // cropHint rectangle lies in the decoded [super]rect.
- final int actualScale = cropHint.height() / wpData.mHeight;
- int scale = 1;
- while (2 * scale <= actualScale) {
- scale *= 2;
- }
- options.inSampleSize = scale;
- options.inJustDecodeBounds = false;
-
- final Rect estimateCrop = new Rect(cropHint);
- estimateCrop.scale(1f / options.inSampleSize);
- final float hRatio = (float) wpData.mHeight / estimateCrop.height();
- final int destHeight = (int) (estimateCrop.height() * hRatio);
- final int destWidth = (int) (estimateCrop.width() * hRatio);
-
- // We estimated an invalid crop, try to adjust the cropHint to get a valid one.
- if (destWidth > GLHelper.getMaxTextureSize()) {
- int newHeight = (int) (wpData.mHeight / hRatio);
- int newWidth = (int) (wpData.mWidth / hRatio);
-
- if (DEBUG) {
- Slog.v(TAG, "Invalid crop dimensions, trying to adjust.");
- }
-
- estimateCrop.set(cropHint);
- estimateCrop.left += (cropHint.width() - newWidth) / 2;
- estimateCrop.top += (cropHint.height() - newHeight) / 2;
- estimateCrop.right = estimateCrop.left + newWidth;
- estimateCrop.bottom = estimateCrop.top + newHeight;
- cropHint.set(estimateCrop);
- estimateCrop.scale(1f / options.inSampleSize);
- }
-
- // We've got the safe cropHint; now we want to scale it properly to
- // the desired rectangle.
- // That's a height-biased operation: make it fit the hinted height.
- final int safeHeight = (int) (estimateCrop.height() * hRatio);
- final int safeWidth = (int) (estimateCrop.width() * hRatio);
-
- if (DEBUG_CROP) {
- Slog.v(TAG, "Decode parameters:");
- Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
- Slog.v(TAG, " down sampling=" + options.inSampleSize
- + ", hRatio=" + hRatio);
- Slog.v(TAG, " dest=" + destWidth + "x" + destHeight);
- Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight);
- Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
- }
-
- //Create a record file and will delete if ImageDecoder work well.
- final String recordName =
- (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
- ? RECORD_FILE : RECORD_LOCK_FILE);
- final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
- record.createNewFile();
- Slog.v(TAG, "record path =" + record.getPath()
- + ", record name =" + record.getName());
-
- final ImageDecoder.Source srcData =
- ImageDecoder.createSource(wallpaper.wallpaperFile);
- final int sampleSize = scale;
- Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
- decoder.setTargetSampleSize(sampleSize);
- decoder.setCrop(estimateCrop);
- });
-
- record.delete();
-
- if (cropped == null) {
- Slog.e(TAG, "Could not decode new wallpaper");
- } else {
- // We are safe to create final crop with safe dimensions now.
- final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
- safeWidth, safeHeight, true);
- if (DEBUG) {
- Slog.v(TAG, "Final extract:");
- Slog.v(TAG, " dims: w=" + wpData.mWidth
- + " h=" + wpData.mHeight);
- Slog.v(TAG, " out: w=" + finalCrop.getWidth()
- + " h=" + finalCrop.getHeight());
- }
-
- f = new FileOutputStream(wallpaper.cropFile);
- bos = new BufferedOutputStream(f, 32*1024);
- finalCrop.compress(Bitmap.CompressFormat.PNG, 100, bos);
- bos.flush(); // don't rely on the implicit flush-at-close when noting success
- success = true;
- }
- } catch (Exception e) {
- if (DEBUG) {
- Slog.e(TAG, "Error decoding crop", e);
- }
- } finally {
- IoUtils.closeQuietly(bos);
- IoUtils.closeQuietly(f);
- }
- }
- }
-
- if (!success) {
- Slog.e(TAG, "Unable to apply new wallpaper");
- wallpaper.cropFile.delete();
- }
-
- if (wallpaper.cropFile.exists()) {
- boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
- if (DEBUG) {
- Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
- }
- }
- }
-
private final Context mContext;
private final WindowManagerInternal mWindowManagerInternal;
private final IPackageManager mIPackageManager;
@@ -912,6 +682,7 @@
@VisibleForTesting
final WallpaperDisplayHelper mWallpaperDisplayHelper;
+ final WallpaperCropper mWallpaperCropper;
private boolean supportsMultiDisplay(WallpaperConnection connection) {
if (connection != null) {
@@ -1567,6 +1338,7 @@
DisplayManager dm = mContext.getSystemService(DisplayManager.class);
dm.registerDisplayListener(mDisplayListener, null /* handler */);
mWallpaperDisplayHelper = new WallpaperDisplayHelper(dm, mWindowManagerInternal);
+ mWallpaperCropper = new WallpaperCropper(mWallpaperDisplayHelper);
mActivityManager = mContext.getSystemService(ActivityManager.class);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
@@ -1617,7 +1389,7 @@
if (DEBUG) {
Slog.i(TAG, "No crop; regenerating from source");
}
- generateCrop(wallpaper);
+ mWallpaperCropper.generateCrop(wallpaper);
}
// Still nothing? Fall back to default.
if (!wallpaper.cropExists()) {
@@ -3479,7 +3251,7 @@
mWallpaperMap.put(userId, wallpaper);
if (!wallpaper.cropExists()) {
if (wallpaper.sourceExists()) {
- generateCrop(wallpaper);
+ mWallpaperCropper.generateCrop(wallpaper);
} else {
Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
}
@@ -3700,7 +3472,7 @@
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
+ " id=" + wallpaper.wallpaperId);
if (success) {
- generateCrop(wallpaper); // based on the new image + metadata
+ mWallpaperCropper.generateCrop(wallpaper); // based on the new image + metadata
bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
wallpaper, null);
}
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
index e145898..cd48f5d 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
@@ -51,6 +51,9 @@
/**
* System service for managing sensing {@link AmbientContextEvent}s on Wearables.
+ *
+ * <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated
+ * separately. </p>
*/
public class WearableSensingManagerService extends
AbstractMasterSystemService<WearableSensingManagerService,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 90ac1aa..fd3f32d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -249,6 +249,7 @@
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ICompatCameraControlCallback;
+import android.app.IScreenCaptureObserver;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.ResultInfo;
@@ -301,6 +302,7 @@
import android.os.LocaleList;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -886,6 +888,8 @@
private AppSaturationInfo mLastAppSaturationInfo;
+ private RemoteCallbackList<IScreenCaptureObserver> mCaptureCallbacks;
+
private final ColorDisplayService.ColorTransformController mColorTransformController =
(matrix, translation) -> mWmService.mH.post(() -> {
synchronized (mWmService.mGlobalLock) {
@@ -7020,6 +7024,41 @@
return mLocusId;
}
+ public void reportScreenCaptured() {
+ if (mCaptureCallbacks != null) {
+ final int n = mCaptureCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IScreenCaptureObserver obs = mCaptureCallbacks.getBroadcastItem(i);
+ try {
+ obs.onScreenCaptured();
+ } catch (RemoteException e) {
+ }
+ }
+ mCaptureCallbacks.finishBroadcast();
+ }
+ }
+
+ public void registerCaptureObserver(IScreenCaptureObserver observer) {
+ synchronized (mWmService.mGlobalLock) {
+ if (mCaptureCallbacks == null) {
+ mCaptureCallbacks = new RemoteCallbackList<IScreenCaptureObserver>();
+ }
+ mCaptureCallbacks.register(observer);
+ }
+ }
+
+ public void unregisterCaptureObserver(IScreenCaptureObserver observer) {
+ synchronized (mWmService.mGlobalLock) {
+ if (mCaptureCallbacks != null) {
+ mCaptureCallbacks.unregister(observer);
+ }
+ }
+ }
+
+ boolean isRegisteredForScreenCaptureCallback() {
+ return mCaptureCallbacks != null && mCaptureCallbacks.getRegisteredCallbackCount() > 0;
+ }
+
void setVoiceSessionLocked(IVoiceInteractionSession session) {
voiceSession = session;
pendingVoiceInteractionStart = false;
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
index 64af9dd..47e78f0 100644
--- a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -72,7 +72,7 @@
}
@GuardedBy("ActivityTaskManagerService.mGlobalLock")
- static boolean shouldBlockActivityStart(int uid) {
+ static boolean shouldRestrictActivitySwitch(int uid) {
return flagEnabledForUid(sAsmRestrictionsEnabled, uid);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d88f719..d6d3dc7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1972,7 +1972,7 @@
);
boolean shouldBlockActivityStart =
- ActivitySecurityModelFeatureFlags.shouldBlockActivityStart(mCallingUid);
+ ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(mCallingUid);
if (ActivitySecurityModelFeatureFlags.shouldShowToast(mCallingUid)) {
UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
@@ -2080,6 +2080,7 @@
reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);
if (mAddingToTask) {
+ clearTopIfNeeded(targetTask, mCallingUid, mStartActivity.getUid(), mLaunchFlags);
return START_SUCCESS;
}
@@ -2112,6 +2113,55 @@
}
/**
+ * If the top activity uid does not match the launched activity, and the launch was not
+ * requested from the top uid, we want to clear out all non matching activities to prevent the
+ * top activity being sandwiched.
+ */
+ private void clearTopIfNeeded(@NonNull Task targetTask, int callingUid, int startingUid,
+ int launchFlags) {
+ if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != FLAG_ACTIVITY_NEW_TASK) {
+ // Launch is from the same task, so must be a top or privileged UID
+ return;
+ }
+
+ ActivityRecord targetTaskTop = targetTask.getTopNonFinishingActivity();
+ if (targetTaskTop != null && targetTaskTop.getUid() != startingUid) {
+ boolean shouldBlockActivityStart = ActivitySecurityModelFeatureFlags
+ .shouldRestrictActivitySwitch(callingUid);
+ int[] finishCount = new int[0];
+ if (shouldBlockActivityStart) {
+ ActivityRecord activity = targetTask.getActivity(
+ ar -> !ar.finishing && ar.isUid(startingUid));
+
+ if (activity == null) {
+ // mStartActivity is not in task, so clear everything
+ activity = mStartActivity;
+ }
+
+ finishCount = new int[1];
+ if (activity != null) {
+ targetTask.performClearTop(activity, launchFlags, finishCount);
+ }
+
+ if (finishCount[0] > 0) {
+ Slog.w(TAG, "Clearing top n: " + finishCount[0] + " activities from task t: "
+ + targetTask + " not matching top uid: " + callingUid);
+ }
+ }
+
+ if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)
+ && (!shouldBlockActivityStart || finishCount[0] > 0)) {
+ UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
+ (shouldBlockActivityStart
+ ? "Top activities cleared by "
+ : "Top activities would be cleared by ")
+ + ActivitySecurityModelFeatureFlags.DOC_LINK,
+ Toast.LENGTH_SHORT).show());
+ }
+ }
+ }
+
+ /**
* Check if the activity being launched is the same as the one currently at the top and it
* should only be launched once.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a927ed3..2f82167 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.BIND_VOICE_INTERACTION;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
@@ -145,6 +146,7 @@
import android.app.IApplicationThread;
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
+import android.app.IScreenCaptureObserver;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -5437,6 +5439,32 @@
}
}
+ @Override
+ public void registerScreenCaptureObserver(IBinder activityToken,
+ IScreenCaptureObserver observer) {
+ mAmInternal.enforceCallingPermission(DETECT_SCREEN_CAPTURE,
+ "registerScreenCaptureObserver");
+ synchronized (mGlobalLock) {
+ ActivityRecord activityRecord = ActivityRecord.forTokenLocked(activityToken);
+ if (activityRecord != null) {
+ activityRecord.registerCaptureObserver(observer);
+ }
+ }
+ }
+
+ @Override
+ public void unregisterScreenCaptureObserver(IBinder activityToken,
+ IScreenCaptureObserver observer) {
+ mAmInternal.enforceCallingPermission(DETECT_SCREEN_CAPTURE,
+ "unregisterScreenCaptureObserver");
+ synchronized (mGlobalLock) {
+ ActivityRecord activityRecord = ActivityRecord.forTokenLocked(activityToken);
+ if (activityRecord != null) {
+ activityRecord.unregisterCaptureObserver(observer);
+ }
+ }
+ }
+
/**
* Returns {@code true} if the process represented by the pid passed as argument is
* instrumented and the instrumentation source was granted with the permission also
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 8149e1c..0f1f51f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -137,6 +137,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Display;
+import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -147,6 +148,7 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
+import com.android.server.UiThread;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.HostingRecord;
import com.android.server.am.UserState;
@@ -1628,16 +1630,16 @@
// Prevent recursion.
return;
}
+ boolean passesAsmChecks = true;
// We may have already checked that the callingUid has additional clearTask privileges, and
// cleared the calling identify. If so, we infer we do not need further restrictions here.
// TODO(b/263368846) Move to live with the rest of the ASM logic.
if (callingUid != SYSTEM_UID) {
- boolean passesAsmChecks = doesTopActivityMatchingUidExistForAsm(task, callingUid,
+ passesAsmChecks = doesTopActivityMatchingUidExistForAsm(task, callingUid,
null);
if (!passesAsmChecks) {
ActivityRecord topActivity = task.getActivity(ar ->
!ar.isState(FINISHING) && !ar.isAlwaysOnTop());
- Slog.i(TAG, "Finishing task from background. t: " + task);
FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
/* caller_uid */
callingUid,
@@ -1676,6 +1678,28 @@
if (task.isPersistable) {
mService.notifyTaskPersisterLocked(null, true);
}
+ if (!passesAsmChecks) {
+ boolean shouldRestrictActivitySwitch =
+ ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(callingUid);
+
+ if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)) {
+ UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
+ (shouldRestrictActivitySwitch
+ ? "Returning home due to "
+ : "Would return home due to ")
+ + ActivitySecurityModelFeatureFlags.DOC_LINK,
+ Toast.LENGTH_SHORT).show());
+ }
+
+ // If the activity switch should be restricted, return home rather than the
+ // previously top task, to prevent users from being confused which app they're
+ // viewing
+ if (shouldRestrictActivitySwitch) {
+ Slog.w(TAG, "Return to home as source uid: " + callingUid
+ + "is not on top of task t: " + task);
+ task.getTaskDisplayArea().moveHomeActivityToTop("taskRemoved");
+ }
+ }
} finally {
task.mInRemoveTask = false;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d65c2f9..2b8b59c 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -901,9 +901,18 @@
* TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled.
*/
static boolean isTaskViewTask(WindowContainer wc) {
- // We use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and
+ // Use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and
// it is not guaranteed to work this logic in the future version.
- return wc instanceof Task && ((Task) wc).mRemoveWithTaskOrganizer;
+ boolean isTaskViewTask = wc instanceof Task && ((Task) wc).mRemoveWithTaskOrganizer;
+ if (isTaskViewTask) {
+ return true;
+ }
+
+ WindowContainer parent = wc.getParent();
+ boolean isParentATaskViewTask = parent != null
+ && parent instanceof Task
+ && ((Task) parent).mRemoveWithTaskOrganizer;
+ return isParentATaskViewTask;
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0bd59a8..1794e2a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5264,6 +5264,11 @@
return b;
}
+ // WARNING: it says `mSurfaceControl` below, but this CHANGES meaning after construction!
+ // DisplayAreas are added in `configureSurface()` *before* `mSurfaceControl` gets replaced
+ // with a wrapper or magnification surface so they end up in the right place; however,
+ // anything added or reparented to "the display" *afterwards* needs to be reparented to
+ // `getWindowinglayer()` (unless it's an overlay DisplayArea).
return b.setName(child.getName())
.setParent(mSurfaceControl);
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 67e188f..73d1ff9d 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -105,6 +105,12 @@
private final ActivityRecord mActivityRecord;
+ /**
+ * Taskbar expanded height. Used to determine when to crop an app window to display the
+ * rounded corners above the expanded taskbar.
+ */
+ private final float mExpandedTaskBarHeight;
+
/*
* WindowContainerListener responsible to make translucent activities inherit
* constraints from the first opaque activity beneath them. It's null for not
@@ -184,6 +190,9 @@
() -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
/* checkDeviceConfig */ true),
PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+
+ mExpandedTaskBarHeight =
+ getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height);
}
/**
@@ -422,7 +431,7 @@
if (w == null) {
return;
}
- adjustBoundsForTaskbar(w, outBounds);
+ adjustBoundsIfNeeded(w, outBounds);
} else {
outBounds.setEmpty();
}
@@ -465,13 +474,13 @@
if (w == null || winHint != null && w != winHint) {
return;
}
- updateRoundedCorners(w);
+ updateRoundedCornersIfNeeded(w);
// If there is another main window that is not an application-starting window, we should
// update rounded corners for it as well, to avoid flickering rounded corners.
final WindowState nonStartingAppW = mActivityRecord.findMainWindow(
/* includeStartingApp= */ false);
if (nonStartingAppW != null && nonStartingAppW != w) {
- updateRoundedCorners(nonStartingAppW);
+ updateRoundedCornersIfNeeded(nonStartingAppW);
}
updateWallpaperForLetterbox(w);
@@ -724,6 +733,7 @@
* <li>Activity is portrait-only.
* <li>Fullscreen window in landscape device orientation.
* <li>Horizontal Reachability is enabled.
+ * <li>Activity fills parent vertically.
* </ul>
*/
private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
@@ -731,10 +741,14 @@
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
&& (parentConfiguration.orientation == ORIENTATION_LANDSCAPE
- && mActivityRecord.getOrientationForReachability() == ORIENTATION_PORTRAIT);
+ && mActivityRecord.getOrientationForReachability() == ORIENTATION_PORTRAIT)
+ // Check whether the activity fills the parent vertically.
+ && parentConfiguration.windowConfiguration.getBounds().height()
+ == mActivityRecord.getBounds().height();
}
- private boolean isHorizontalReachabilityEnabled() {
+ @VisibleForTesting
+ boolean isHorizontalReachabilityEnabled() {
return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
@@ -746,6 +760,7 @@
* <li>Activity is landscape-only.
* <li>Fullscreen window in portrait device orientation.
* <li>Vertical Reachability is enabled.
+ * <li>Activity fills parent horizontally.
* </ul>
*/
private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
@@ -753,10 +768,14 @@
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
&& (parentConfiguration.orientation == ORIENTATION_PORTRAIT
- && mActivityRecord.getOrientationForReachability() == ORIENTATION_LANDSCAPE);
+ && mActivityRecord.getOrientationForReachability() == ORIENTATION_LANDSCAPE)
+ // Check whether the activity fills the parent horizontally.
+ && parentConfiguration.windowConfiguration.getBounds().width()
+ == mActivityRecord.getBounds().width();
}
- private boolean isVerticalReachabilityEnabled() {
+ @VisibleForTesting
+ boolean isVerticalReachabilityEnabled() {
return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
@@ -765,8 +784,8 @@
return isSurfaceReadyAndVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed()
// Check for FLAG_SHOW_WALLPAPER explicitly instead of using
// WindowContainer#showWallpaper because the later will return true when this
- // activity is using blurred wallpaper for letterbox backgroud.
- && (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
+ // activity is using blurred wallpaper for letterbox background.
+ && (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) == 0;
}
@VisibleForTesting
@@ -818,106 +837,107 @@
return mLetterboxConfiguration.getLetterboxBackgroundColor();
}
- private void updateRoundedCorners(WindowState mainWindow) {
+ private void updateRoundedCornersIfNeeded(final WindowState mainWindow) {
final SurfaceControl windowSurface = mainWindow.getSurfaceControl();
- if (windowSurface != null && windowSurface.isValid()) {
- final Transaction transaction = mActivityRecord.getSyncTransaction();
-
- if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
- // We don't want corner radius on the window.
- // In the case the ActivityRecord requires a letterboxed animation we never want
- // rounded corners on the window because rounded corners are applied at the
- // animation-bounds surface level and rounded corners on the window would interfere
- // with that leading to unexpected rounded corner positioning during the animation.
- transaction
- .setWindowCrop(windowSurface, null)
- .setCornerRadius(windowSurface, 0);
- return;
- }
-
- Rect cropBounds = null;
-
- if (hasVisibleTaskbar(mainWindow)) {
- cropBounds = new Rect(mActivityRecord.getBounds());
-
- // Rounded corners should be displayed above the taskbar.
- // It is important to call adjustBoundsForTaskbarUnchecked before offsetTo
- // because taskbar bounds are in screen coordinates
- adjustBoundsForTaskbarUnchecked(mainWindow, cropBounds);
-
- // Activity bounds are in screen coordinates while (0,0) for activity's surface
- // control is at the top left corner of an app window so offsetting bounds
- // accordingly.
- cropBounds.offsetTo(0, 0);
- }
-
- transaction
- .setWindowCrop(windowSurface, cropBounds)
- .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow));
+ if (windowSurface == null || !windowSurface.isValid()) {
+ return;
}
+
+ // cropBounds must be non-null for the cornerRadius to be ever applied.
+ mActivityRecord.getSyncTransaction()
+ .setCrop(windowSurface, getCropBoundsIfNeeded(mainWindow))
+ .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow));
}
- private boolean requiresRoundedCorners(WindowState mainWindow) {
- final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
+ @VisibleForTesting
+ @Nullable
+ Rect getCropBoundsIfNeeded(final WindowState mainWindow) {
+ if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+ // We don't want corner radius on the window.
+ // In the case the ActivityRecord requires a letterboxed animation we never want
+ // rounded corners on the window because rounded corners are applied at the
+ // animation-bounds surface level and rounded corners on the window would interfere
+ // with that leading to unexpected rounded corner positioning during the animation.
+ return null;
+ }
+ final Rect cropBounds = new Rect(mActivityRecord.getBounds());
+
+ // It is important to call {@link #adjustBoundsIfNeeded} before {@link cropBounds.offsetTo}
+ // because taskbar bounds used in {@link #adjustBoundsIfNeeded}
+ // are in screen coordinates
+ adjustBoundsIfNeeded(mainWindow, cropBounds);
+
+ // ActivityRecord bounds are in screen coordinates while (0,0) for activity's surface
+ // control is in the top left corner of an app window so offsetting bounds
+ // accordingly.
+ cropBounds.offsetTo(0, 0);
+ return cropBounds;
+ }
+
+ private boolean requiresRoundedCorners(final WindowState mainWindow) {
return isLetterboxedNotForDisplayCutout(mainWindow)
- && mLetterboxConfiguration.isLetterboxActivityCornersRounded()
- && taskbarInsetsSource != null;
+ && mLetterboxConfiguration.isLetterboxActivityCornersRounded();
}
// Returns rounded corners radius the letterboxed activity should have based on override in
// R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii.
- // Device corners can be different on the right and left sides but we use the same radius
+ // Device corners can be different on the right and left sides, but we use the same radius
// for all corners for consistency and pick a minimal bottom one for consistency with a
// taskbar rounded corners.
- int getRoundedCornersRadius(WindowState mainWindow) {
- if (!requiresRoundedCorners(mainWindow)) {
+ int getRoundedCornersRadius(final WindowState mainWindow) {
+ if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
return 0;
}
+ final int radius;
if (mLetterboxConfiguration.getLetterboxActivityCornersRadius() >= 0) {
- return mLetterboxConfiguration.getLetterboxActivityCornersRadius();
+ radius = mLetterboxConfiguration.getLetterboxActivityCornersRadius();
+ } else {
+ final InsetsState insetsState = mainWindow.getInsetsState();
+ radius = Math.min(
+ getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT),
+ getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT));
}
- final InsetsState insetsState = mainWindow.getInsetsState();
- return Math.min(
- getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT),
- getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT));
+ final float scale = mainWindow.mInvGlobalScale;
+ return (scale != 1f && scale > 0f) ? (int) (scale * radius) : radius;
}
/**
- * Returns whether the taskbar is visible. Returns false if the window is in immersive mode,
- * since the user can swipe to show/hide the taskbar as an overlay.
+ * Returns the taskbar in case it is visible and expanded in height, otherwise returns null.
*/
- private boolean hasVisibleTaskbar(WindowState mainWindow) {
- final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
-
- return taskbarInsetsSource != null
- && taskbarInsetsSource.isVisible();
+ @VisibleForTesting
+ @Nullable
+ InsetsSource getExpandedTaskbarOrNull(final WindowState mainWindow) {
+ final InsetsSource taskbar = mainWindow.getInsetsState().peekSource(
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ if (taskbar != null && taskbar.isVisible()
+ && taskbar.getFrame().height() >= mExpandedTaskBarHeight) {
+ return taskbar;
+ }
+ return null;
}
- private InsetsSource getTaskbarInsetsSource(WindowState mainWindow) {
- final InsetsState insetsState = mainWindow.getInsetsState();
- return insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
- }
-
- private void adjustBoundsForTaskbar(WindowState mainWindow, Rect bounds) {
+ private void adjustBoundsIfNeeded(final WindowState mainWindow, final Rect bounds) {
// Rounded corners should be displayed above the taskbar. When taskbar is hidden,
// an insets frame is equal to a navigation bar which shouldn't affect position of
// rounded corners since apps are expected to handle navigation bar inset.
// This condition checks whether the taskbar is visible.
// Do not crop the taskbar inset if the window is in immersive mode - the user can
// swipe to show/hide the taskbar as an overlay.
- if (hasVisibleTaskbar(mainWindow)) {
- adjustBoundsForTaskbarUnchecked(mainWindow, bounds);
+ // Adjust the bounds only in case there is an expanded taskbar,
+ // otherwise the rounded corners will be shown behind the navbar.
+ final InsetsSource expandedTaskbarOrNull = getExpandedTaskbarOrNull(mainWindow);
+ if (expandedTaskbarOrNull != null) {
+ // Rounded corners should be displayed above the expanded taskbar.
+ bounds.bottom = Math.min(bounds.bottom, expandedTaskbarOrNull.getFrame().top);
}
- }
- private void adjustBoundsForTaskbarUnchecked(WindowState mainWindow, Rect bounds) {
- // Rounded corners should be displayed above the taskbar.
- bounds.bottom =
- Math.min(bounds.bottom, getTaskbarInsetsSource(mainWindow).getFrame().top);
- scaleIfNeeded(bounds);
+ final float scale = mainWindow.mInvGlobalScale;
+ if (scale != 1f && scale > 0f) {
+ bounds.scale(scale);
+ }
}
private int getInsetsStateCornerRadius(
@@ -1259,20 +1279,4 @@
mInheritedSizeCompatScale = 1f;
mInheritedCompatDisplayInsets = null;
}
-
- private void scaleIfNeeded(Rect bounds) {
- if (boundsNeedToScale()) {
- bounds.scale(1.0f / mActivityRecord.getCompatScale());
- }
- }
-
- private boolean boundsNeedToScale() {
- if (hasInheritedLetterboxBehavior()) {
- return mIsInheritedInSizeCompatMode
- && mInheritedSizeCompatScale < 1.0f;
- } else {
- return mActivityRecord.inSizeCompatMode()
- && mActivityRecord.getCompatScale() < 1.0f;
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a76d836..1b59d8d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3271,12 +3271,17 @@
// We intend to let organizer manage task visibility but it doesn't
// have enough information until we finish shell transitions.
// In the mean time we do an easy fix here.
- final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean visible = isVisible();
+ final boolean show = visible || isAnimating(TRANSITION | PARENTS | CHILDREN);
if (mSurfaceControl != null) {
if (show != mLastSurfaceShowing) {
t.setVisibility(mSurfaceControl, show);
}
}
+ // Only show the overlay if the task has other visible children
+ if (mOverlayHost != null) {
+ mOverlayHost.setVisibility(t, visible);
+ }
mLastSurfaceShowing = show;
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 7d3367f..7b56b0c 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1650,6 +1650,12 @@
// DisplayContent is the "root", so we reinterpret it's wc as the window layer
// making the parent surface the displaycontent's surface.
return wc.getSurfaceControl();
+ } else if (wc.getParent().asDisplayContent() != null) {
+ // DisplayContent is kinda split into 2 pieces, the "real root" and the
+ // "windowing layer". So if the parent of the window is DC, then it really belongs on
+ // the windowing layer (unless it's an overlay display area, but those can't be in
+ // transitions anyways).
+ return wc.getParent().asDisplayContent().getWindowingLayer();
}
return wc.getParent().getSurfaceControl();
}
diff --git a/services/core/java/com/android/server/wm/TrustedOverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
index 975b21c..88c410b 100644
--- a/services/core/java/com/android/server/wm/TrustedOverlayHost.java
+++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
@@ -80,6 +80,12 @@
}
}
+ void setVisibility(SurfaceControl.Transaction t, boolean visible) {
+ if (mSurfaceControl != null) {
+ t.setVisibility(mSurfaceControl, visible);
+ }
+ }
+
void addOverlay(SurfaceControlViewHost.SurfacePackage p, SurfaceControl currentParent) {
requireOverlaySurfaceControl();
mOverlays.add(p);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8767096..a596eed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -26,6 +26,7 @@
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STATUS_BAR_SERVICE;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
@@ -168,6 +169,7 @@
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -427,7 +429,7 @@
* @see #ENABLE_SHELL_TRANSITIONS
*/
public static final boolean sEnableShellTransitions =
- SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, false);
+ SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, true);
/**
* Allows a fullscreen windowing mode activity to launch in its desired orientation directly
@@ -3174,7 +3176,8 @@
/**
* Moves the given display to the top. If it cannot be moved to the top this method does
- * nothing.
+ * nothing (e.g. if the display has the flag FLAG_STEAL_TOP_FOCUS_DISABLED set).
+ * @param displayId The display to move to the top.
*/
void moveDisplayToTopInternal(int displayId) {
synchronized (mGlobalLock) {
@@ -3189,14 +3192,6 @@
return;
}
- if (mPerDisplayFocusEnabled) {
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT,
- "Not moving display (displayId=%d) to top. Top focused displayId=%d. "
- + "Reason: config_perDisplayFocusEnabled", displayId,
- mRoot.getTopFocusedDisplayContent().getDisplayId());
- return;
- }
-
// Nothing prevented us from moving the display to the top. Let's do it!
displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
displayContent, true /* includingParents */);
@@ -9454,4 +9449,55 @@
public void markSurfaceSyncGroupReady(IBinder syncGroupToken) {
mSurfaceSyncGroupController.markSyncGroupReady(syncGroupToken);
}
+
+ private ArraySet<ActivityRecord> getVisibleActivityRecords(int displayId) {
+ ArraySet<ActivityRecord> result = new ArraySet<>();
+ synchronized (mGlobalLock) {
+ ArraySet<ComponentName> addedActivities = new ArraySet<>();
+ DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.forAllWindows(
+ (w) -> {
+ if (w.isVisible()
+ && w.isDisplayed()
+ && w.mActivityRecord != null
+ && !addedActivities.contains(
+ w.mActivityRecord.mActivityComponent)
+ && w.mActivityRecord.isVisible()
+ && w.isVisibleNow()) {
+ addedActivities.add(w.mActivityRecord.mActivityComponent);
+ result.add(w.mActivityRecord);
+ }
+ },
+ true /* traverseTopToBottom */);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Must be called when a screenshot is taken via hardware chord.
+ *
+ * Notifies all registered visible activities that have registered for screencapture callback,
+ * Returns a list of visible apps component names.
+ */
+ @Override
+ public List<ComponentName> notifyScreenshotListeners(int displayId) {
+ // make sure caller is SysUI.
+ if (!checkCallingPermission(STATUS_BAR_SERVICE,
+ "notifyScreenshotListeners()")) {
+ throw new SecurityException("Requires STATUS_BAR_SERVICE permission");
+ }
+ synchronized (mGlobalLock) {
+ ArraySet<ComponentName> notifiedApps = new ArraySet<>();
+ ArraySet<ActivityRecord> visibleApps = getVisibleActivityRecords(displayId);
+ for (ActivityRecord ar : visibleApps) {
+ if (ar.isRegisteredForScreenCaptureCallback()) {
+ ar.reportScreenCaptured();
+ notifiedApps.add(ar.mActivityComponent);
+ }
+ }
+ return List.copyOf(notifiedApps);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 2980c76..7dfc132 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1015,7 +1015,7 @@
/**
* Returns display UI context list which there is any app window shows or starting activities
- * int this process.
+ * in this process.
*/
public void getDisplayContextsWithErrorDialogs(List<Context> displayContexts) {
if (displayContexts == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 223352e..33af563 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -6241,7 +6241,6 @@
@Override
public void handleTapOutsideFocusInsideSelf() {
- final DisplayContent displayContent = getDisplayContent();
mWmService.moveDisplayToTopInternal(getDisplayId());
mWmService.handleTaskFocusChange(getTask(), mActivityRecord);
}
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index d3d69ae..4af685e 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -146,6 +146,7 @@
// vmas vector, instead it iterates on it until the end.
class VmaBatchCreator {
const std::vector<Vma>* sourceVmas;
+ const int totalVmasInSource;
// This is the destination array where batched VMAs will be stored
// it gets encapsulated into a VmaBatch which is the object
// meant to be used by client code.
@@ -156,8 +157,13 @@
uint64_t currentOffset_;
public:
- VmaBatchCreator(const std::vector<Vma>* vmasToBatch, struct iovec* destVmasVec)
- : sourceVmas(vmasToBatch), destVmas(destVmasVec), currentIndex_(0), currentOffset_(0) {}
+ VmaBatchCreator(const std::vector<Vma>* vmasToBatch, struct iovec* destVmasVec,
+ int vmasInSource)
+ : sourceVmas(vmasToBatch),
+ totalVmasInSource(vmasInSource),
+ destVmas(destVmasVec),
+ currentIndex_(0),
+ currentOffset_(0) {}
int currentIndex() { return currentIndex_; }
uint64_t currentOffset() { return currentOffset_; }
@@ -177,7 +183,7 @@
// Add VMAs to the batch up until we consumed all the VMAs or
// reached any imposed limit of VMAs per batch.
- while (indexInBatch < MAX_VMAS_PER_BATCH && currentIndex_ < vmas.size()) {
+ while (indexInBatch < MAX_VMAS_PER_BATCH && currentIndex_ < totalVmasInSource) {
uint64_t vmaStart = vmas[currentIndex_].start + currentOffset_;
uint64_t vmaSize = vmas[currentIndex_].end - vmaStart;
uint64_t bytesAvailableInBatch = MAX_BYTES_PER_BATCH - totalBytesInBatch;
@@ -272,8 +278,9 @@
//
// If any VMA fails compaction due to -EINVAL it will be skipped and continue.
// However, if it fails for any other reason, it will bail out and forward the error
-static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType) {
- if (vmas.empty()) {
+static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType,
+ int totalVmas) {
+ if (totalVmas == 0) {
return 0;
}
@@ -286,7 +293,7 @@
struct iovec destVmas[MAX_VMAS_PER_BATCH];
VmaBatch batch;
- VmaBatchCreator batcher(&vmas, destVmas);
+ VmaBatchCreator batcher(&vmas, destVmas, totalVmas);
int64_t totalBytesProcessed = 0;
while (batcher.createNextBatch(batch)) {
@@ -346,34 +353,53 @@
// Returns the total number of bytes compacted on success. On error
// returns process_madvise errno code or if compaction was cancelled
// it returns ERROR_COMPACTION_CANCELLED.
+//
+// Not thread safe. We reuse vectors so we assume this is called only
+// on one thread at most.
static int64_t compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) {
cancelRunningCompaction.store(false);
-
+ static std::string mapsBuffer;
ATRACE_BEGIN("CollectVmas");
ProcMemInfo meminfo(pid);
- std::vector<Vma> pageoutVmas, coldVmas;
- auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) {
+ static std::vector<Vma> pageoutVmas(2000), coldVmas(2000);
+ int coldVmaIndex = 0;
+ int pageoutVmaIndex = 0;
+ auto vmaCollectorCb = [&vmaToAdviseFunc, &pageoutVmaIndex, &coldVmaIndex](const Vma& vma) {
int advice = vmaToAdviseFunc(vma);
switch (advice) {
case MADV_COLD:
- coldVmas.push_back(vma);
+ if (coldVmaIndex < coldVmas.size()) {
+ coldVmas[coldVmaIndex] = vma;
+ } else {
+ coldVmas.push_back(vma);
+ }
+ ++coldVmaIndex;
break;
case MADV_PAGEOUT:
- pageoutVmas.push_back(vma);
+ if (pageoutVmaIndex < pageoutVmas.size()) {
+ pageoutVmas[pageoutVmaIndex] = vma;
+ } else {
+ pageoutVmas.push_back(vma);
+ }
+ ++pageoutVmaIndex;
break;
}
};
- meminfo.ForEachVmaFromMaps(vmaCollectorCb);
+ meminfo.ForEachVmaFromMaps(vmaCollectorCb, mapsBuffer);
ATRACE_END();
+#ifdef DEBUG_COMPACTION
+ ALOGE("Total VMAs sent for compaction anon=%d file=%d", pageoutVmaIndex,
+ coldVmaIndex);
+#endif
- int64_t pageoutBytes = compactMemory(pageoutVmas, pid, MADV_PAGEOUT);
+ int64_t pageoutBytes = compactMemory(pageoutVmas, pid, MADV_PAGEOUT, pageoutVmaIndex);
if (pageoutBytes < 0) {
// Error, just forward it.
cancelRunningCompaction.store(false);
return pageoutBytes;
}
- int64_t coldBytes = compactMemory(coldVmas, pid, MADV_COLD);
+ int64_t coldBytes = compactMemory(coldVmas, pid, MADV_COLD, coldVmaIndex);
if (coldBytes < 0) {
// Error, just forward it.
cancelRunningCompaction.store(false);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 4c42791..36cb898 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -174,6 +174,7 @@
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
+ private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
DeviceAdminInfo info;
@@ -332,6 +333,9 @@
// The package policy for Cross Profile Contacts Search
PackagePolicy mManagedProfileContactsAccess = null;
+ // The package policy for Credential Manager
+ PackagePolicy mCredentialManagerPolicy = null;
+
public String mAlwaysOnVpnPackage;
public boolean mAlwaysOnVpnLockdown;
boolean mCommonCriteriaMode;
@@ -647,6 +651,8 @@
mManagedProfileCallerIdAccess);
writePackagePolicy(out, TAG_CROSS_PROFILE_CONTACTS_SEARCH_POLICY,
mManagedProfileContactsAccess);
+ writePackagePolicy(out, TAG_CREDENTIAL_MANAGER_POLICY,
+ mCredentialManagerPolicy);
if (mManagedSubscriptionsPolicy != null) {
out.startTag(null, TAG_MANAGED_SUBSCRIPTIONS_POLICY);
mManagedSubscriptionsPolicy.saveToXml(out);
@@ -958,6 +964,8 @@
mManagedProfileContactsAccess = readPackagePolicy(parser);
} else if (TAG_MANAGED_SUBSCRIPTIONS_POLICY.equals(tag)) {
mManagedSubscriptionsPolicy = ManagedSubscriptionsPolicy.readFromXml(parser);
+ } else if (TAG_CREDENTIAL_MANAGER_POLICY.equals(tag)) {
+ mCredentialManagerPolicy = readPackagePolicy(parser);
} else {
Slogf.w(LOG_TAG, "Unknown admin tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
@@ -1332,6 +1340,9 @@
dumpPackagePolicy(pw, "managedProfileContactsPolicy",
mManagedProfileContactsAccess);
+ dumpPackagePolicy(pw, "credentialManagerPolicy",
+ mCredentialManagerPolicy);
+
pw.print("isParent=");
pw.println(isParent);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
deleted file mode 100644
index 834f65f..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.devicepolicy;
-
-import android.accounts.Account;
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.admin.DevicePolicyDrawableResource;
-import android.app.admin.DevicePolicySafetyChecker;
-import android.app.admin.DevicePolicyStringResource;
-import android.app.admin.FullyManagedDeviceProvisioningParams;
-import android.app.admin.IDevicePolicyManager;
-import android.app.admin.ManagedProfileProvisioningParams;
-import android.app.admin.ParcelableResource;
-import android.content.ComponentName;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import com.android.server.SystemService;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Defines the required interface for IDevicePolicyManager implemenation.
- *
- * <p>The interface consists of public parts determined by {@link IDevicePolicyManager} and also
- * several package private methods required by internal infrastructure.
- *
- * <p>Whenever adding an AIDL method to {@link IDevicePolicyManager}, an empty override method
- * should be added here to avoid build breakage in downstream branches.
- */
-abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
-
- private static final String TAG = BaseIDevicePolicyManager.class.getSimpleName();
-
- /**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
- *
- * @see {@link SystemService#onBootPhase}.
- */
- abstract void systemReady(int phase);
- /**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} when a new user starts.
- *
- * @see {@link SystemService#onUserStarting}
- */
- abstract void handleStartUser(int userId);
- /**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being unlocked.
- *
- * @see {@link SystemService#onUserUnlocking}
- */
- abstract void handleUnlockUser(int userId);
- /**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} after a user is being unlocked.
- *
- * @see {@link SystemService#onUserUnlocked}
- */
- abstract void handleOnUserUnlocked(int userId);
- /**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being stopped.
- *
- * @see {@link SystemService#onUserStopping}
- */
- abstract void handleStopUser(int userId);
-
- /**
- * Sets the {@link DevicePolicySafetyChecker}.
- *
- * <p>Currently, it's called only by {@code SystemServer} on
- * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}
- */
- public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
- Slog.w(TAG, "setDevicePolicySafetyChecker() not implemented by " + getClass());
- }
-
- public void clearSystemUpdatePolicyFreezePeriodRecord() {
- }
-
- public boolean setKeyGrantForApp(ComponentName admin, String callerPackage, String alias,
- String packageName, boolean hasGrant) {
- return false;
- }
-
- public void setLocationEnabled(ComponentName who, boolean locationEnabled) {}
-
- public boolean isOrganizationOwnedDeviceWithManagedProfile() {
- return false;
- }
-
- public int getPersonalAppsSuspendedReasons(ComponentName admin) {
- return 0;
- }
-
- public void setPersonalAppsSuspended(ComponentName admin, boolean suspended) {
- }
-
- public void setManagedProfileMaximumTimeOff(ComponentName admin, long timeoutMs) {
- }
-
- public long getManagedProfileMaximumTimeOff(ComponentName admin) {
- return 0;
- }
-
- @Override
- public void acknowledgeDeviceCompliant() {}
-
- @Override
- public boolean isComplianceAcknowledgementRequired() {
- return false;
- }
-
- public boolean canProfileOwnerResetPasswordWhenLocked(int userId) {
- return false;
- }
-
- public String getEnrollmentSpecificId(String callerPackage) {
- return "";
- }
-
- public void setOrganizationIdForUser(
- @NonNull String callerPackage, @NonNull String enterpriseId, int userId) {}
-
- public UserHandle createAndProvisionManagedProfile(
- @NonNull ManagedProfileProvisioningParams provisioningParams, String callerPackage) {
- return null;
- }
-
- public void finalizeWorkProfileProvisioning(
- UserHandle managedProfileUser, Account migratedAccount) {
-
- }
-
- public void provisionFullyManagedDevice(
- FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
- }
-
- @Override
- public void setDeviceOwnerType(@NonNull ComponentName admin, int deviceOwnerType) {
- }
-
- @Override
- public int getDeviceOwnerType(@NonNull ComponentName admin) {
- return 0;
- }
-
- public void resetDefaultCrossProfileIntentFilters(@UserIdInt int userId) {}
-
- public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
- return false;
- }
-
- @Override
- public boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant) {
- return false;
- }
-
- @Override
- public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
- return false;
- }
-
- @Override
- public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
-
- @Override
- public void resetDrawables(@NonNull List<String> drawableIds){}
-
- @Override
- public ParcelableResource getDrawable(
- String drawableId, String drawableStyle, String drawableSource) {
- return null;
- }
-
- @Override
- public void setStrings(@NonNull List<DevicePolicyStringResource> strings){}
-
- @Override
- public void resetStrings(@NonNull List<String> stringIds){}
-
- @Override
- public ParcelableResource getString(String stringId) {
- return null;
- }
-
- @Override
- public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
- return false;
- }
-
- @Override
- public List<UserHandle> getPolicyManagedProfiles(UserHandle userHandle) {
- return Collections.emptyList();
- }
-}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1406a396..7d1b5ca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -221,6 +221,7 @@
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.FullyManagedDeviceProvisioningParams;
+import android.app.admin.IDevicePolicyManager;
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.NetworkEvent;
@@ -442,7 +443,7 @@
/**
* Implementation of the device policy APIs.
*/
-public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
protected static final String LOG_TAG = "DevicePolicyManager";
@@ -739,6 +740,10 @@
private static final String KEEP_PROFILES_RUNNING_FLAG = "enable_keep_profiles_running";
private static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = false;
+ private static final String ENABLE_WORK_PROFILE_TELEPHONY_FLAG =
+ "enable_work_profile_telephony";
+ private static final boolean DEFAULT_WORK_PROFILE_TELEPHONY_FLAG = false;
+
// TODO(b/261999445) remove the flag after rollout.
private static final String HEADLESS_FLAG = "headless";
private static final boolean DEFAULT_HEADLESS_FLAG = true;
@@ -920,23 +925,24 @@
private final ArrayList<Object> mPendingUserCreatedCallbackTokens = new ArrayList<>();
public static final class Lifecycle extends SystemService {
- private BaseIDevicePolicyManager mService;
+ private DevicePolicyManagerService mService;
public Lifecycle(Context context) {
super(context);
String dpmsClassName = context.getResources()
.getString(R.string.config_deviceSpecificDevicePolicyManagerService);
if (TextUtils.isEmpty(dpmsClassName)) {
- dpmsClassName = DevicePolicyManagerService.class.getName();
- }
- try {
- Class<?> serviceClass = Class.forName(dpmsClassName);
- Constructor<?> constructor = serviceClass.getConstructor(Context.class);
- mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
- } catch (Exception e) {
- throw new IllegalStateException(
- "Failed to instantiate DevicePolicyManagerService with class name: "
- + dpmsClassName, e);
+ mService = new DevicePolicyManagerService(context);
+ } else {
+ try {
+ Class<?> serviceClass = Class.forName(dpmsClassName);
+ Constructor<?> constructor = serviceClass.getConstructor(Context.class);
+ mService = (DevicePolicyManagerService) constructor.newInstance(context);
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to instantiate DevicePolicyManagerService with class name: "
+ + dpmsClassName, e);
+ }
}
}
@@ -1095,13 +1101,13 @@
// (ACTION_DATE_CHANGED), or when manual clock adjustment is made
// (ACTION_TIME_CHANGED)
updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
- final int userId = getManagedUserId(mUserManager.getMainUser().getIdentifier());
+ final int userId = getManagedUserId(getMainUserId());
if (userId >= 0) {
updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
}
} else if (ACTION_PROFILE_OFF_DEADLINE.equals(action)) {
Slogf.i(LOG_TAG, "Profile off deadline alarm was triggered");
- final int userId = getManagedUserId(mUserManager.getMainUser().getIdentifier());
+ final int userId = getManagedUserId(getMainUserId());
if (userId >= 0) {
updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
} else {
@@ -1348,7 +1354,6 @@
}
}
- @Override
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
CallerIdentity callerIdentity = getCallerIdentity();
Preconditions.checkCallAuthorization(mIsAutomotive || isAdb(callerIdentity), "can only set "
@@ -3090,7 +3095,6 @@
}
@VisibleForTesting
- @Override
void systemReady(int phase) {
if (!mHasFeature) {
return;
@@ -3100,7 +3104,9 @@
onLockSettingsReady();
loadAdminDataAsync();
mOwners.systemReady();
- applyManagedSubscriptionsPolicyIfRequired();
+ if (isWorkProfileTelephonyFlagEnabled()) {
+ applyManagedSubscriptionsPolicyIfRequired();
+ }
break;
case SystemService.PHASE_ACTIVITY_MANAGER_READY:
synchronized (getLockObject()) {
@@ -3289,7 +3295,6 @@
}
}
- @Override
void handleStartUser(int userId) {
synchronized (getLockObject()) {
pushScreenCapturePolicy(userId);
@@ -3337,7 +3342,6 @@
targetUserId, protectedPackages));
}
- @Override
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
if (isCoexistenceFlagEnabled()) {
@@ -3345,12 +3349,10 @@
}
}
- @Override
void handleOnUserUnlocked(int userId) {
showNewUserDisclaimerIfNecessary(userId);
}
- @Override
void handleStopUser(int userId) {
updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
mDeviceAdminServiceController.stopServicesForUser(userId, /* actionForLog= */ "stop-user");
@@ -7018,8 +7020,9 @@
}
mLockSettingsInternal.refreshStrongAuthTimeout(parentId);
- clearManagedSubscriptionsPolicy();
-
+ if (isWorkProfileTelephonyFlagEnabled()) {
+ clearManagedSubscriptionsPolicy();
+ }
Slogf.i(LOG_TAG, "Cleaning up device-wide policies done.");
}
@@ -8879,6 +8882,15 @@
}
}
+ private @UserIdInt int getMainUserId() {
+ UserHandle mainUser = mUserManager.getMainUser();
+ if (mainUser == null) {
+ Slogf.d(LOG_TAG, "getMainUserId(): no main user, returning USER_SYSTEM");
+ return UserHandle.USER_SYSTEM;
+ }
+ return mainUser.getIdentifier();
+ }
+
// TODO(b/240562946): Remove api as owner name is not used.
/**
* Returns the "name" of the device owner. It'll work for non-DO users too, but requires
@@ -10123,6 +10135,9 @@
synchronized (mSubscriptionsChangedListenerLock) {
pw.println("Subscription changed listener : " + mSubscriptionsChangedListener);
}
+ pw.println(
+ "Flag enable_work_profile_telephony : " + isWorkProfileTelephonyFlagEnabled());
+
mHandler.post(() -> handleDump(pw));
dumpResources(pw);
}
@@ -14301,6 +14316,46 @@
}
@Override
+ public void setCredentialManagerPolicy(PackagePolicy policy) {
+ if (!mHasFeature) {
+ return;
+ }
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canWriteCredentialManagerPolicy(caller));
+
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ if (Objects.equals(admin.mCredentialManagerPolicy, policy)) {
+ return;
+ }
+
+ admin.mCredentialManagerPolicy = policy;
+ saveSettingsLocked(caller.getUserId());
+ }
+ }
+
+ private boolean canWriteCredentialManagerPolicy(CallerIdentity caller) {
+ return (isProfileOwner(caller) && isManagedProfile(caller.getUserId()))
+ || isDefaultDeviceOwner(caller)
+ || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ }
+
+ @Override
+ public PackagePolicy getCredentialManagerPolicy() {
+ if (!mHasFeature) {
+ return null;
+ }
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ canWriteCredentialManagerPolicy(caller) || canQueryAdminPolicy(caller));
+
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ return (admin != null) ? admin.mCredentialManagerPolicy : null;
+ }
+ }
+
+ @Override
public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) {
if (policy != null) {
// throws exception if policy type is invalid
@@ -20095,6 +20150,13 @@
DEFAULT_KEEP_PROFILES_RUNNING_FLAG);
}
+ private static boolean isWorkProfileTelephonyFlagEnabled() {
+ return DeviceConfig.getBoolean(
+ NAMESPACE_DEVICE_POLICY_MANAGER,
+ ENABLE_WORK_PROFILE_TELEPHONY_FLAG,
+ DEFAULT_WORK_PROFILE_TELEPHONY_FLAG);
+ }
+
@Override
public void setMtePolicy(int flags) {
final Set<Integer> allowedModes =
@@ -20175,10 +20237,12 @@
@Override
public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
- synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOfOrganizationOwnedDeviceLocked();
- if (admin != null && admin.mManagedSubscriptionsPolicy != null) {
- return admin.mManagedSubscriptionsPolicy;
+ if (isWorkProfileTelephonyFlagEnabled()) {
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOfOrganizationOwnedDeviceLocked();
+ if (admin != null && admin.mManagedSubscriptionsPolicy != null) {
+ return admin.mManagedSubscriptionsPolicy;
+ }
}
}
return new ManagedSubscriptionsPolicy(
@@ -20187,9 +20251,13 @@
@Override
public void setManagedSubscriptionsPolicy(ManagedSubscriptionsPolicy policy) {
+ if (!isWorkProfileTelephonyFlagEnabled()) {
+ throw new UnsupportedOperationException("This api is not enabled");
+ }
CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller),
- "This policy can only be set by a profile owner on an organization-owned device.");
+ "This policy can only be set by a profile owner on an organization-owned "
+ + "device.");
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerLocked(caller.getUserId());
@@ -20307,4 +20375,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index 9fe090a..3976a70 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -36,5 +36,10 @@
}
]
}
+ ],
+ "kernel-presubmit": [
+ {
+ "name": "CtsIncrementalInstallHostTestCases"
+ }
]
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3725756..a15c6d2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1021,9 +1021,7 @@
Runnable runnable = new Runnable() {
@Override
public void run() {
- synchronized (this) {
- ShutdownThread.rebootOrShutdown(null, reboot, reason);
- }
+ ShutdownThread.rebootOrShutdown(null, reboot, reason);
}
};
@@ -1446,6 +1444,9 @@
boolean isArc = context.getPackageManager().hasSystemFeature(
"org.chromium.arc");
+ boolean isTv = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_LEANBACK);
+
boolean enableVrService = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index f7efcd1..e711cab 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -32,7 +32,6 @@
"services.people",
"services.usage",
"guava",
- "guava-android-testlib",
"androidx.test.core",
"androidx.test.ext.truth",
"androidx.test.runner",
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 681bfcf..f915298 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -51,6 +51,7 @@
"kotlin-test",
"mockingservicestests-utils-mockito",
"mockito-target-extended-minus-junit4",
+ "platform-compat-test-rules",
"platform-test-annotations",
"service-blobstore",
"service-jobscheduler",
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 33ac735..ea0481e 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -43,6 +43,9 @@
<!-- needed by TrustManagerServiceTest to access LockSettings' secure storage -->
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+ <!-- needed by GameManagerServiceTest because GameManager creates a UidObserver -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+
<application android:testOnly="true"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/res/raw/backup_file_with_long_name b/services/tests/mockingservicestests/res/raw/backup_file_with_long_name
similarity index 100%
rename from services/tests/servicestests/res/raw/backup_file_with_long_name
rename to services/tests/mockingservicestests/res/raw/backup_file_with_long_name
Binary files differ
diff --git a/services/tests/servicestests/res/raw/backup_telephony_no_password b/services/tests/mockingservicestests/res/raw/backup_telephony_no_password
similarity index 100%
rename from services/tests/servicestests/res/raw/backup_telephony_no_password
rename to services/tests/mockingservicestests/res/raw/backup_telephony_no_password
Binary files differ
diff --git a/services/tests/servicestests/res/raw/backup_telephony_with_password b/services/tests/mockingservicestests/res/raw/backup_telephony_with_password
similarity index 100%
rename from services/tests/servicestests/res/raw/backup_telephony_with_password
rename to services/tests/mockingservicestests/res/raw/backup_telephony_with_password
Binary files differ
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index e2b25ef..57c5a6e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -128,6 +128,7 @@
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
+import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
@@ -508,7 +509,7 @@
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
verify(mBatteryManager).isCharging();
- setTareEnabled(false);
+ setTareEnabled(EconomyManager.ENABLED_MODE_OFF);
mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> captor =
@@ -658,10 +659,10 @@
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
}
- private void setTareEnabled(boolean enabled) {
- when(mEconomyManagerInternal.isEnabled(eq(AlarmManagerEconomicPolicy.POLICY_ALARM)))
- .thenReturn(enabled);
- mService.mConstants.onTareEnabledStateChanged(enabled);
+ private void setTareEnabled(int enabledMode) {
+ when(mEconomyManagerInternal.getEnabledMode(eq(AlarmManagerEconomicPolicy.POLICY_ALARM)))
+ .thenReturn(enabledMode);
+ mService.mConstants.onTareEnabledModeChanged(enabledMode);
}
/**
@@ -2091,7 +2092,7 @@
@Test
public void tareThrottling() {
- setTareEnabled(true);
+ setTareEnabled(EconomyManager.ENABLED_MODE_ON);
final ArgumentCaptor<EconomyManagerInternal.AffordabilityChangeListener> listenerCaptor =
ArgumentCaptor.forClass(EconomyManagerInternal.AffordabilityChangeListener.class);
final ArgumentCaptor<EconomyManagerInternal.ActionBill> billCaptor =
@@ -3418,9 +3419,18 @@
}
@Test
- public void tareEventPushed() throws Exception {
- setTareEnabled(true);
+ public void tareEventPushed_on() throws Exception {
+ setTareEnabled(EconomyManager.ENABLED_MODE_ON);
+ runTareEventPushed();
+ }
+ @Test
+ public void tareEventPushed_shadow() throws Exception {
+ setTareEnabled(EconomyManager.ENABLED_MODE_SHADOW);
+ runTareEventPushed();
+ }
+
+ private void runTareEventPushed() throws Exception {
for (int i = 0; i < 10; i++) {
final int type = (i % 2 == 1) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 05cad16..64e39ef 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -194,7 +194,7 @@
public void init_withDeviceConfigSetsParameters() {
// When the DeviceConfig already has a flag value stored (note this test will need to
// change if the default value changes from false).
- assertThat(CachedAppOptimizer.DEFAULT_USE_COMPACTION).isFalse();
+ assertThat(CachedAppOptimizer.DEFAULT_USE_COMPACTION).isTrue();
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_USE_COMPACTION, "true", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -372,9 +372,8 @@
CachedAppOptimizer.KEY_USE_COMPACTION, "foobar", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
- // Then we set the default.
- assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_COMPACTION);
+ // Invalid value is mapped to false
+ assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(false);
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index c4c50424..32243f0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -36,6 +36,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -45,6 +46,7 @@
import android.Manifest;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.GameManager;
import android.app.GameModeConfiguration;
import android.app.GameModeInfo;
@@ -2212,4 +2214,106 @@
assertEquals(expectedInterventionListOutput,
gameManagerService.getInterventionList(mPackageName, USER_ID_1));
}
+
+ @Test
+ public void testGamePowerMode_gamePackage() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_twoGames() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages1 = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages1);
+ String someGamePkg = "some.game";
+ String[] packages2 = {someGamePkg};
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ HashMap<Integer, Boolean> powerState = new HashMap<>();
+ doAnswer(inv -> powerState.put(inv.getArgument(0), inv.getArgument(1)))
+ .when(mMockPowerManager).setPowerMode(anyInt(), anyBoolean());
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ assertTrue(powerState.get(Mode.GAME));
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ assertTrue(powerState.get(Mode.GAME));
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ assertFalse(powerState.get(Mode.GAME));
+ }
+
+ @Test
+ public void testGamePowerMode_twoGamesOverlap() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages1 = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages1);
+ String someGamePkg = "some.game";
+ String[] packages2 = {someGamePkg};
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
+ }
+
+ @Test
+ public void testGamePowerMode_released() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
+ }
+
+ @Test
+ public void testGamePowerMode_noPackage() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_notAGamePackage() throws Exception {
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {"someapp"};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_notAGamePackageNotReleased() throws Exception {
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {"someapp"};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, false);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
index 98e895a..cd5ac7bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -35,6 +35,8 @@
import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -754,6 +756,32 @@
verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
}
+ @Test
+ public void testIsUidInForegroundForBackgroundState() {
+ procStateBuilder(UID)
+ .backgroundState()
+ .update();
+ assertFalse(mIntf.isUidInForeground(UID));
+
+ procStateBuilder(UID)
+ .nonExistentState()
+ .update();
+ assertFalse(mIntf.isUidInForeground(UID));
+ }
+
+ @Test
+ public void testIsUidInForegroundForForegroundState() {
+ procStateBuilder(UID)
+ .topState()
+ .update();
+ assertTrue(mIntf.isUidInForeground(UID));
+
+ procStateBuilder(UID)
+ .foregroundServiceState()
+ .update();
+ assertTrue(mIntf.isUidInForeground(UID));
+ }
+
public void testUidStateChangedCallback(int initialState, int finalState) {
int initialUidState = processStateToUidState(initialState);
int finalUidState = processStateToUidState(finalState);
@@ -806,7 +834,7 @@
private AppOpsUidStateTracker mIntf;
private int mUid;
private int mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
- private int mCapability = 0;
+ private int mCapability = ActivityManager.PROCESS_CAPABILITY_NONE;
private UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid) {
mUid = uid;
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/DataChangedJournalTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/DataChangedJournalTest.java
index 9daa4ba..4b0b760 100644
--- a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/DataChangedJournalTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.backup;
diff --git a/services/tests/servicestests/src/com/android/server/backup/ProcessedPackagesJournalTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/ProcessedPackagesJournalTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/ProcessedPackagesJournalTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/ProcessedPackagesJournalTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
index 5800aca..2c5ae37 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/internal/BackupHandlerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/internal/BackupHandlerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/internal/BackupHandlerTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/internal/BackupHandlerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/internal/LifecycleOperationStorageTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/internal/LifecycleOperationStorageTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/internal/LifecycleOperationStorageTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/internal/LifecycleOperationStorageTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java
index 00c6391..4d6845c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformAdbRestoreTaskTest.java
@@ -25,7 +25,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.mockingservicestests.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/mockingservicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/transport/TransportStatusCallbackTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/transport/TransportStatusCallbackTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/transport/TransportStatusCallbackTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/transport/TransportStatusCallbackTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 48b0aad..6093f4b 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -58,7 +58,7 @@
@RunWith(AndroidJUnit4.class)
public class BackupEligibilityRulesTest {
private static final String CUSTOM_BACKUP_AGENT_NAME = "custom.backup.agent";
- private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
+ private static final String TEST_PACKAGE_NAME = "com.android.frameworks.mockingservicestests";
private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/FileUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/FileUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
rename to services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index e2536f8..30c6975 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -51,7 +51,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.mockingservicestests.R;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.restore.PerformAdbRestoreTask;
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index f2cba40..3d36c1c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -18,6 +18,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
@@ -80,6 +82,8 @@
@Mock
private DisplayBlanker mDisplayBlankerMock;
@Mock
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadataMock;
+ @Mock
private LogicalDisplay mLogicalDisplayMock;
@Mock
private DisplayDevice mDisplayDeviceMock;
@@ -169,7 +173,7 @@
mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
- });
+ }, mHighBrightnessModeMetadataMock);
when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
// send a display power request
@@ -251,4 +255,35 @@
});
when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
}
+
+ @Test
+ public void testDisplayBrightnessFollowers() {
+ setUpDisplay(DISPLAY_ID, UNIQUE_DISPLAY_ID);
+
+ DisplayPowerController2 defaultDpc = new DisplayPowerController2(
+ mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
+ mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
+ mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
+ }, mHighBrightnessModeMetadataMock);
+ DisplayPowerController2 followerDpc = new DisplayPowerController2(
+ mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
+ mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
+ mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
+ }, mHighBrightnessModeMetadataMock);
+
+ defaultDpc.addDisplayBrightnessFollower(followerDpc);
+
+ defaultDpc.setBrightness(0.3f);
+ assertEquals(defaultDpc.getBrightnessInfo().brightness,
+ followerDpc.getBrightnessInfo().brightness, 0);
+
+ defaultDpc.setBrightness(0.6f);
+ assertEquals(defaultDpc.getBrightnessInfo().brightness,
+ followerDpc.getBrightnessInfo().brightness, 0);
+
+ float brightness = 0.1f;
+ defaultDpc.clearDisplayBrightnessFollowers();
+ defaultDpc.setBrightness(brightness);
+ assertNotEquals(brightness, followerDpc.getBrightnessInfo().brightness, 0);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 4f8cb88..b6388cc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -19,6 +19,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
@@ -84,6 +86,8 @@
@Mock
private DisplayDevice mDisplayDeviceMock;
@Mock
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadataMock;
+ @Mock
private BrightnessTracker mBrightnessTrackerMock;
@Mock
private BrightnessSetting mBrightnessSettingMock;
@@ -151,7 +155,7 @@
mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
- });
+ }, mHighBrightnessModeMetadataMock);
when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
// send a display power request
@@ -233,4 +237,35 @@
});
when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
}
+
+ @Test
+ public void testDisplayBrightnessFollowers() {
+ setUpDisplay(DISPLAY_ID, UNIQUE_DISPLAY_ID);
+
+ DisplayPowerController defaultDpc = new DisplayPowerController(
+ mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
+ mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
+ mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
+ }, mHighBrightnessModeMetadataMock);
+ DisplayPowerController followerDpc = new DisplayPowerController(
+ mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
+ mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
+ mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
+ }, mHighBrightnessModeMetadataMock);
+
+ defaultDpc.addDisplayBrightnessFollower(followerDpc);
+
+ defaultDpc.setBrightness(0.3f);
+ assertEquals(defaultDpc.getBrightnessInfo().brightness,
+ followerDpc.getBrightnessInfo().brightness, 0);
+
+ defaultDpc.setBrightness(0.6f);
+ assertEquals(defaultDpc.getBrightnessInfo().brightness,
+ followerDpc.getBrightnessInfo().brightness, 0);
+
+ float brightness = 0.1f;
+ defaultDpc.clearDisplayBrightnessFollowers();
+ defaultDpc.setBrightness(brightness);
+ assertNotEquals(brightness, followerDpc.getBrightnessInfo().brightness, 0);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index d2ee9ff..6df54a6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
@@ -132,6 +133,98 @@
}
@Test
+ public void testCanRunInBatterySaver_regular() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar")).build();
+ JobStatus job = createJobStatus(jobInfo);
+ assertFalse(job.canRunInBatterySaver());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInBatterySaver());
+ }
+
+ @Test
+ public void testCanRunInBatterySaver_expedited() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setExpedited(true)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ markExpeditedQuotaApproved(job, true);
+ assertTrue(job.canRunInBatterySaver());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInBatterySaver());
+
+ // Reset the job
+ job = createJobStatus(jobInfo);
+ markExpeditedQuotaApproved(job, true);
+ spyOn(job);
+ when(job.shouldTreatAsExpeditedJob()).thenReturn(false);
+ job.startedAsExpeditedJob = true;
+ assertTrue(job.canRunInBatterySaver());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInBatterySaver());
+ }
+
+ @Test
+ public void testCanRunInBatterySaver_userInitiated() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setUserInitiated(true)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ assertTrue(job.canRunInBatterySaver());
+ // User-initiated privilege should trump bs & doze requirement.
+ job.disallowRunInBatterySaverAndDoze();
+ assertTrue(job.canRunInBatterySaver());
+ }
+
+ @Test
+ public void testCanRunInDoze_regular() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar")).build();
+ JobStatus job = createJobStatus(jobInfo);
+ assertFalse(job.canRunInDoze());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInDoze());
+ }
+
+ @Test
+ public void testCanRunInDoze_expedited() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setExpedited(true)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ markExpeditedQuotaApproved(job, true);
+ assertTrue(job.canRunInDoze());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInDoze());
+
+ // Reset the job
+ job = createJobStatus(jobInfo);
+ markExpeditedQuotaApproved(job, true);
+ spyOn(job);
+ when(job.shouldTreatAsExpeditedJob()).thenReturn(false);
+ job.startedAsExpeditedJob = true;
+ assertTrue(job.canRunInDoze());
+ job.disallowRunInBatterySaverAndDoze();
+ assertFalse(job.canRunInDoze());
+ }
+
+ @Test
+ public void testCanRunInDoze_userInitiated() {
+ final JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setUserInitiated(true)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ assertTrue(job.canRunInDoze());
+ // User-initiated privilege should trump bs & doze requirement.
+ job.disallowRunInBatterySaverAndDoze();
+ assertTrue(job.canRunInDoze());
+ }
+
+ @Test
public void testMediaBackupExemption_lateConstraint() {
final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
.addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
@@ -907,6 +1000,13 @@
assertFalse(job.readinessStatusWithConstraint(CONSTRAINT_FLEXIBLE, false));
}
+ private void markExpeditedQuotaApproved(JobStatus job, boolean isApproved) {
+ if (job.isRequestedExpeditedJob()) {
+ job.setExpeditedJobQuotaApproved(sElapsedRealtimeClock.millis(), isApproved);
+ job.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), isApproved);
+ }
+ }
+
private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
job.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index c46ebf2..71280ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.when;
+import android.app.tare.EconomyManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -89,7 +90,7 @@
.mockStatic(LocalServices.class)
.startMocking();
when(mIrs.getLock()).thenReturn(new Object());
- when(mIrs.isEnabled()).thenReturn(true);
+ when(mIrs.getEnabledMode()).thenReturn(EconomyManager.ENABLED_MODE_ON);
when(mIrs.getInstalledPackages()).thenReturn(mInstalledPackages);
when(mAnalyst.getReports()).thenReturn(mReports);
mTestFileDir = new File(getContext().getFilesDir(), "scribe_test");
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 19b5ad6..de54537 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -427,7 +427,8 @@
doReturn(true).when(mService)
.bindWallpaperComponentLocked(any(), anyBoolean(), anyBoolean(), any(), any());
doNothing().when(mService).saveSettingsLocked(wallpaper.userId);
- doNothing().when(mService).generateCrop(wallpaper);
+ spyOn(mService.mWallpaperCropper);
+ doNothing().when(mService.mWallpaperCropper).generateCrop(wallpaper);
// timestamps of {ACTION_WALLPAPER_CHANGED, onWallpaperColorsChanged}
final long[] timestamps = new long[2];
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 80305fa..ced2a4b 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -60,7 +60,6 @@
"truth-prebuilt",
"junit",
"junit-params",
- "platform-compat-test-rules",
"ActivityContext",
"coretests-aidl",
],
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index 450cc40..908e717 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -36,6 +36,8 @@
useParentsContacts='false'
crossProfileIntentFilterAccessControl='20'
crossProfileIntentResolutionStrategy='0'
+ mediaSharedWithParent='true'
+ credentialShareableWithParent='false'
/>
</profile-type>
<profile-type name='custom.test.1' max-allowed-per-parent='14' />
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
index 653ed1a..0b25f38 100644
--- a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -17,39 +17,85 @@
package com.android.server;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.job.JobScheduler;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.ComponentInfoInternal;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemProperties;
+import android.provider.DeviceConfig;
+import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class BinaryTransparencyServiceTest {
+ private static final String TAG = "BinaryTransparencyServiceTest";
+
private Context mContext;
private BinaryTransparencyService mBinaryTransparencyService;
private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
+ private DeviceConfig.Properties mOriginalBiometricsFlags;
+
+ @Mock
+ private BinaryTransparencyService.BiometricLogger mBiometricLogger;
+ @Mock
+ private FingerprintManager mFpManager;
+ @Mock
+ private FaceManager mFaceManager;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
mContext = spy(ApplicationProvider.getApplicationContext());
- mBinaryTransparencyService = new BinaryTransparencyService(mContext);
+ mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger);
mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
+ mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS);
+
+ when(mContext.getSystemService(FingerprintManager.class)).thenReturn(mFpManager);
+ when(mContext.getSystemService(FaceManager.class)).thenReturn(mFaceManager);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ try {
+ DeviceConfig.setProperties(mOriginalBiometricsFlags);
+ } catch (DeviceConfig.BadConfigException e) {
+ Log.e(TAG, "Failed to reset biometrics flags to the original values before test. "
+ + e);
+ }
}
private void prepSignedInfo() {
@@ -120,4 +166,105 @@
}
}
+ @Test
+ public void testCollectBiometricProperties_disablesFeature() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
+ Boolean.FALSE.toString(),
+ false /* makeDefault */);
+
+ mBinaryTransparencyService.collectBiometricProperties();
+
+ verify(mFpManager, never()).getSensorPropertiesInternal();
+ verify(mFaceManager, never()).getSensorProperties();
+ }
+
+ @Test
+ public void testCollectBiometricProperties_enablesFeature() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
+ Boolean.TRUE.toString(),
+ false /* makeDefault */);
+
+ mBinaryTransparencyService.collectBiometricProperties();
+
+ verify(mFpManager, times(1)).getSensorPropertiesInternal();
+ verify(mFaceManager, times(1)).getSensorProperties();
+ }
+
+ @Test
+ public void testCollectBiometricProperties_enablesFeature_logsFingerprintProperties() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
+ Boolean.TRUE.toString(),
+ false /* makeDefault */);
+ final List<FingerprintSensorPropertiesInternal> props = List.of(
+ new FingerprintSensorPropertiesInternal(
+ 1 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ List.of(new ComponentInfoInternal("sensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */,
+ "1.01" /* firmwareVersion */, "00000001" /* serialNumber */,
+ "" /* softwareVersion */)),
+ FingerprintSensorProperties.TYPE_REAR,
+ true /* resetLockoutRequiresHardwareAuthToken */));
+ when(mFpManager.getSensorPropertiesInternal()).thenReturn(props);
+
+ mBinaryTransparencyService.collectBiometricProperties();
+
+ verify(mBiometricLogger, times(1)).logStats(
+ eq(1) /* sensorId */,
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FINGERPRINT),
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_REAR),
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_STRONG),
+ eq("sensor") /* componentId */,
+ eq("vendor/model/revision") /* hardwareVersion */,
+ eq("1.01") /* firmwareVersion */,
+ eq("00000001") /* serialNumber */,
+ eq("") /* softwareVersion */
+ );
+ }
+
+ @Test
+ public void testCollectBiometricProperties_enablesFeature_logsFaceProperties() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
+ Boolean.TRUE.toString(),
+ false /* makeDefault */);
+ final List<FaceSensorProperties> props = List.of(FaceSensorProperties.from(
+ new FaceSensorPropertiesInternal(
+ 1 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 1 /* maxEnrollmentsPerUser */,
+ List.of(new ComponentInfoInternal("sensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */,
+ "1.01" /* firmwareVersion */, "00000001" /* serialNumber */,
+ "" /* softwareVersion */)),
+ FaceSensorProperties.TYPE_RGB,
+ true /* supportsFaceDetection */,
+ true /* supportsSelfIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */)));
+ when(mFaceManager.getSensorProperties()).thenReturn(props);
+
+ mBinaryTransparencyService.collectBiometricProperties();
+
+ verify(mBiometricLogger, times(1)).logStats(
+ eq(1) /* sensorId */,
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FACE),
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FACE_RGB),
+ eq(FrameworkStatsLog
+ .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_CONVENIENCE),
+ eq("sensor") /* componentId */,
+ eq("vendor/model/revision") /* hardwareVersion */,
+ eq("1.01") /* firmwareVersion */,
+ eq("00000001") /* serialNumber */,
+ eq("") /* softwareVersion */
+ );
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 448ffe5..6831902 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -16,13 +16,19 @@
package com.android.server.accessibility;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+import static com.android.server.accessibility.AccessibilityManagerService.MENU_SERVICE_RELATIVE_CLASS_NAME;
import static com.google.common.truth.Truth.assertThat;
@@ -93,6 +99,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
/**
* APCT tests for {@link AccessibilityManagerService}.
@@ -514,6 +521,113 @@
ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
}
+ @Test
+ public void testMigrateA11yMenu_ResetSingularComponentToDefaultState() {
+ final ComponentName componentName =
+ ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME);
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
+ eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(
+ List.of(createResolveInfo(componentName)));
+
+ mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState());
+
+ verify(mMockPackageManager).setComponentEnabledSetting(componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ @Test
+ public void testMigrateA11yMenu_DoNothing_WhenNoMenuComponents() {
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
+ eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of());
+
+ mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState());
+
+ verify(mMockPackageManager, never()).setComponentEnabledSetting(any(),
+ anyInt(), anyInt());
+ }
+
+ @Test
+ public void testMigrateA11yMenu_DoNothing_WhenTooManyMenuComponents() {
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
+ eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of(
+ createResolveInfo(ComponentName.createRelative("external1",
+ MENU_SERVICE_RELATIVE_CLASS_NAME)),
+ createResolveInfo(ComponentName.createRelative("external2",
+ MENU_SERVICE_RELATIVE_CLASS_NAME)),
+ createResolveInfo(ComponentName.createRelative("external3",
+ MENU_SERVICE_RELATIVE_CLASS_NAME))));
+
+ mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState());
+
+ verify(mMockPackageManager, never()).setComponentEnabledSetting(any(),
+ anyInt(), anyInt());
+ }
+
+ @Test
+ public void testMigrateA11yMenu_DoNothing_WhenNoMenuInSystem() {
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
+ eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of(
+ createResolveInfo(ComponentName.createRelative("external1",
+ MENU_SERVICE_RELATIVE_CLASS_NAME)),
+ createResolveInfo(ComponentName.createRelative("external2",
+ MENU_SERVICE_RELATIVE_CLASS_NAME))));
+
+ mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState());
+
+ verify(mMockPackageManager, never()).setComponentEnabledSetting(any(),
+ anyInt(), anyInt());
+ }
+
+ @Test
+ public void testMigrateA11yMenu_PerformsMigration() {
+ final ComponentName menuOutsideSystem =
+ ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME);
+ final String[] migratedSettings = {
+ ACCESSIBILITY_BUTTON_TARGETS,
+ ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ ENABLED_ACCESSIBILITY_SERVICES
+ };
+ // Start the user with Menu-outside-system enabled,
+ for (String setting : migratedSettings) {
+ Settings.Secure.putStringForUser(
+ mTestableContext.getContentResolver(),
+ setting,
+ menuOutsideSystem.flattenToShortString(),
+ mA11yms.getCurrentUserIdLocked());
+ }
+ // and both Menu versions present.
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
+ eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of(
+ createResolveInfo(menuOutsideSystem),
+ createResolveInfo(ACCESSIBILITY_MENU_IN_SYSTEM)));
+
+ mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState());
+
+ // Menu-outside-system should be disabled,
+ verify(mMockPackageManager).setComponentEnabledSetting(menuOutsideSystem,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ // and all settings should migrated to Menu-in-system.
+ for (String setting : migratedSettings) {
+ ComponentName componentName = ComponentName.unflattenFromString(
+ Settings.Secure.getStringForUser(
+ mTestableContext.getContentResolver(),
+ setting,
+ mA11yms.getCurrentUserIdLocked()));
+ assertThat(componentName).isEqualTo(ACCESSIBILITY_MENU_IN_SYSTEM);
+ }
+ }
+
+ private static ResolveInfo createResolveInfo(ComponentName componentName) {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = new ServiceInfo();
+ resolveInfo.serviceInfo.packageName = componentName.getPackageName();
+ resolveInfo.serviceInfo.name = componentName.getClassName();
+ return resolveInfo;
+ }
+
private void mockManageAccessibilityGranted(TestableContext context) {
context.getTestablePermissions().setPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
PackageManager.PERMISSION_GRANTED);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
index c84c2c2..b5e0e07 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
@@ -28,6 +28,7 @@
import android.accessibilityservice.AccessibilityTrace;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.os.Handler;
import android.view.accessibility.AccessibilityEvent;
@@ -35,6 +36,7 @@
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.android.server.wm.WindowManagerInternal;
@@ -79,7 +81,10 @@
@Before
public void setup() {
+ final Resources resources = getInstrumentation().getContext().getResources();
MockitoAnnotations.initMocks(this);
+ when(mMockContext.getResources()).thenReturn(resources);
+
mAccessibilityServiceInfo = new AccessibilityServiceInfo();
mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME,
mAccessibilityServiceInfo, CONNECTION_ID , new Handler(
diff --git a/services/tests/servicestests/src/com/android/server/backup/OWNERS b/services/tests/servicestests/src/com/android/server/backup/OWNERS
deleted file mode 100644
index d99779e..0000000
--- a/services/tests/servicestests/src/com/android/server/backup/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/backup/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index aec70f4..6216c66 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -16,16 +16,23 @@
package com.android.server.biometrics;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
+import static android.Manifest.permission.TEST_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,11 +60,14 @@
import com.android.internal.R;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Stubber;
import java.util.List;
@@ -65,11 +75,13 @@
@SmallTest
public class AuthServiceTest {
- private static final String TAG = "AuthServiceTest";
private static final String TEST_OP_PACKAGE_NAME = "test_package";
private AuthService mAuthService;
+ @Rule
+ public MockitoRule mockitorule = MockitoJUnit.rule();
+
@Mock
private Context mContext;
@Mock
@@ -97,8 +109,6 @@
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
-
// Placeholder test config
final String[] config = {
"0:2:15", // ID0:Fingerprint:Strong
@@ -123,10 +133,13 @@
when(mInjector.getIrisService()).thenReturn(mIrisService);
when(mInjector.getAppOps(any())).thenReturn(mAppOpsManager);
when(mInjector.isHidlDisabled(any())).thenReturn(false);
+
+ setInternalAndTestBiometricPermissions(mContext, false /* hasPermission */);
}
@Test
public void testRegisterNullService_doesNotRegister() throws Exception {
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
// Config contains Fingerprint, Iris, Face, but services are all null
@@ -260,6 +273,40 @@
}
@Test
+ public void testAuthenticate_throwsWhenUsingTestConfigurations() {
+ final PromptInfo promptInfo = mock(PromptInfo.class);
+ when(promptInfo.containsPrivateApiConfigurations()).thenReturn(false);
+ when(promptInfo.containsTestConfigurations()).thenReturn(true);
+
+ testAuthenticate_throwsWhenUsingTestConfigurations(promptInfo);
+ }
+
+ @Test
+ public void testAuthenticate_throwsWhenUsingPrivateApis() {
+ final PromptInfo promptInfo = mock(PromptInfo.class);
+ when(promptInfo.containsPrivateApiConfigurations()).thenReturn(true);
+ when(promptInfo.containsTestConfigurations()).thenReturn(false);
+
+ testAuthenticate_throwsWhenUsingTestConfigurations(promptInfo);
+ }
+
+ private void testAuthenticate_throwsWhenUsingTestConfigurations(PromptInfo promptInfo) {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ assertThrows(SecurityException.class, () -> {
+ mAuthService.mImpl.authenticate(
+ null /* token */,
+ 10 /* sessionId */,
+ 2 /* userId */,
+ mReceiver,
+ TEST_OP_PACKAGE_NAME,
+ promptInfo);
+ waitForIdle();
+ });
+ }
+
+ @Test
public void testCanAuthenticate_callsBiometricServiceCanAuthenticate() throws Exception {
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
@@ -283,8 +330,10 @@
}
@Test
- public void testHasEnrolledBiometrics_callsBiometricServiceHasEnrolledBiometrics() throws
- Exception {
+ public void testHasEnrolledBiometrics_callsBiometricServiceHasEnrolledBiometrics()
+ throws Exception {
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
+
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
@@ -307,6 +356,8 @@
@Test
public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()
throws Exception {
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
+
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
@@ -320,6 +371,20 @@
eq(callback), eq(UserHandle.getCallingUserId()));
}
+ private static void setInternalAndTestBiometricPermissions(
+ Context context, boolean hasPermission) {
+ for (String p : List.of(TEST_BIOMETRIC, MANAGE_BIOMETRIC, USE_BIOMETRIC_INTERNAL)) {
+ when(context.checkCallingPermission(eq(p))).thenReturn(hasPermission
+ ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+ when(context.checkCallingOrSelfPermission(eq(p))).thenReturn(hasPermission
+ ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+ final Stubber doPermCheck =
+ hasPermission ? doNothing() : doThrow(SecurityException.class);
+ doPermCheck.when(context).enforceCallingPermission(eq(p), any());
+ doPermCheck.when(context).enforceCallingOrSelfPermission(eq(p), any());
+ }
+ }
+
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
new file mode 100644
index 0000000..c7fb97f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.datatransfer.contextsync;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.platform.test.annotations.Presubmit;
+import android.telecom.Call;
+import android.telecom.ParcelableCall;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidTestingRunner.class)
+public class CrossDeviceCallTest {
+
+ private static final String CALLER_DISPLAY_NAME = "name";
+ private static final String CONTACT_DISPLAY_NAME = "contact";
+
+ @Test
+ public void updateCallDetails_uninitialized() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.UNKNOWN_STATUS);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls()).isEmpty();
+ }
+
+ @Test
+ public void updateCallDetails_ringing() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_RINGING,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.RINGING);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
+ android.companion.Telecom.Call.REJECT,
+ android.companion.Telecom.Call.SILENCE));
+ }
+
+ @Test
+ public void updateCallDetails_ongoing() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ONGOING);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.MUTE,
+ android.companion.Telecom.Call.PUT_ON_HOLD));
+ }
+
+ @Test
+ public void updateCallDetails_holding() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_HOLDING,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ON_HOLD);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.TAKE_OFF_HOLD));
+ }
+
+ @Test
+ public void updateCallDetails_cannotHold() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ONGOING);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.MUTE));
+ }
+
+ @Test
+ public void updateCallDetails_cannotMute() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, Call.Details.CAPABILITY_HOLD));
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ONGOING);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.PUT_ON_HOLD));
+ }
+
+ @Test
+ public void updateCallDetails_transitionRingingToOngoing() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_RINGING,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status for ringing state").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.RINGING);
+ assertWithMessage("Wrong controls for ringing state").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
+ android.companion.Telecom.Call.REJECT,
+ android.companion.Telecom.Call.SILENCE));
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ assertWithMessage("Wrong status for active state").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ONGOING);
+ assertWithMessage("Wrong controls for active state").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.MUTE,
+ android.companion.Telecom.Call.PUT_ON_HOLD));
+ }
+
+ @Test
+ public void updateSilencedIfRinging_ringing_silenced() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_RINGING,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ crossDeviceCall.updateSilencedIfRinging();
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.RINGING_SILENCED);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
+ android.companion.Telecom.Call.REJECT));
+ }
+
+ @Test
+ public void updateSilencedIfRinging_notRinging_notSilenced() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
+ Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
+ crossDeviceCall.updateSilencedIfRinging();
+ assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.ONGOING);
+ assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.END,
+ android.companion.Telecom.Call.MUTE,
+ android.companion.Telecom.Call.PUT_ON_HOLD));
+ }
+
+ @Test
+ public void getReadableCallerId_enterpriseCall_adminBlocked_ott() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = true;
+ crossDeviceCall.mIsOtt = true;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(true);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CALLER_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_enterpriseCall_adminUnblocked_ott() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = true;
+ crossDeviceCall.mIsOtt = true;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(false);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CALLER_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_enterpriseCall_adminBlocked_pstn() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = true;
+ crossDeviceCall.mIsOtt = false;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(true);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CALLER_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_nonEnterpriseCall_adminBlocked_ott() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = false;
+ crossDeviceCall.mIsOtt = true;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(true);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CALLER_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_nonEnterpriseCall_adminUnblocked_ott() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = false;
+ crossDeviceCall.mIsOtt = true;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(false);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CALLER_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_nonEnterpriseCall_adminBlocked_pstn() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = false;
+ crossDeviceCall.mIsOtt = false;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(true);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CONTACT_DISPLAY_NAME);
+ }
+
+ @Test
+ public void getReadableCallerId_nonEnterpriseCall_adminUnblocked_pstn() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext().getPackageManager(), /* call= */
+ null, /* callAudioState= */ null);
+ crossDeviceCall.mIsEnterprise = false;
+ crossDeviceCall.mIsOtt = false;
+ crossDeviceCall.updateCallDetails(
+ createCallDetails(Call.STATE_ACTIVE, /* capabilities= */ 0));
+
+ final String result = crossDeviceCall.getReadableCallerId(false);
+
+ assertWithMessage("Wrong caller id").that(result)
+ .isEqualTo(CONTACT_DISPLAY_NAME);
+ }
+
+ private Call.Details createCallDetails(int state, int capabilities) {
+ final ParcelableCall.ParcelableCallBuilder parcelableCallBuilder =
+ new ParcelableCall.ParcelableCallBuilder();
+ parcelableCallBuilder.setCallerDisplayName(CALLER_DISPLAY_NAME);
+ parcelableCallBuilder.setContactDisplayName(CONTACT_DISPLAY_NAME);
+ parcelableCallBuilder.setCapabilities(capabilities);
+ parcelableCallBuilder.setState(state);
+ parcelableCallBuilder.setConferenceableCallIds(Collections.emptyList());
+ return Call.Details.createFromParcelableCall(parcelableCallBuilder.createParcelableCall());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 6a4435f..3791b35 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -634,6 +634,8 @@
@Test
public void onAppsOnVirtualDeviceChanged_multipleVirtualDevices_listenersNotified() {
+ createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
+
ArraySet<Integer> uidsOnDevice1 = new ArraySet<>(Arrays.asList(UID_1, UID_2));
ArraySet<Integer> uidsOnDevice2 = new ArraySet<>(Arrays.asList(UID_3, UID_4));
mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
@@ -645,7 +647,7 @@
new ArraySet<>(Arrays.asList(UID_1, UID_2)));
// Notifies that the running apps on the second virtual device has changed.
- mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId() + 1, uidsOnDevice2);
+ mVdms.notifyRunningAppsChanged(VIRTUAL_DEVICE_ID_2, uidsOnDevice2);
TestableLooper.get(this).processAllMessages();
// The union of the apps running on both virtual devices are sent to the listeners.
verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
@@ -1059,6 +1061,16 @@
}
@Test
+ public void closedDevice_lateCallToRunningAppsChanged_isIgnored() {
+ mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
+ int deviceId = mDeviceImpl.getDeviceId();
+ mDeviceImpl.close();
+ mVdms.notifyRunningAppsChanged(deviceId, Sets.newArraySet(UID_1));
+ TestableLooper.get(this).processAllMessages();
+ verify(mAppsOnVirtualDeviceListener, never()).onAppsOnAnyVirtualDeviceChanged(any());
+ }
+
+ @Test
public void sendKeyEvent_noFd() {
assertThrows(
IllegalArgumentException.class,
@@ -1583,6 +1595,33 @@
verify(mSoundEffectListener).onPlaySoundEffect(AudioManager.FX_KEY_CLICK);
}
+ @Test
+ public void getDisplayIdsForDevice_invalidDeviceId_emptyResult() {
+ ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_2);
+ assertThat(displayIds).isEmpty();
+ }
+
+ @Test
+ public void getDisplayIdsForDevice_noDisplays_emptyResult() {
+ ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
+ assertThat(displayIds).isEmpty();
+ }
+
+ @Test
+ public void getDisplayIdsForDevice_oneDisplay_resultContainsCorrectDisplayId() {
+ mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1);
+ ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
+ assertThat(displayIds).containsExactly(DISPLAY_ID_1);
+ }
+
+ @Test
+ public void getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds() {
+ mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1);
+ mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_2);
+ ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
+ assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2);
+ }
+
private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid) {
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
.setBlockedActivities(getBlockedActivities())
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 4998a6c..60483f1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -134,6 +134,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.KeyChain;
import android.security.keystore.AttestationUtils;
@@ -259,6 +260,8 @@
private static final String PROFILE_OFF_SUSPENSION_TITLE = "suspension_title";
private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text";
private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text";
+ private static final String FLAG_ENABLE_WORK_PROFILE_TELEPHONY =
+ "enable_work_profile_telephony";
@Before
public void setUp() throws Exception {
@@ -4982,7 +4985,8 @@
public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
-
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "true", false);
// Even if the caller is the managed profile, the current user is the user 0
when(getServices().iactivityManager.getCurrentUser())
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
@@ -5043,6 +5047,8 @@
verify(getServices().packageManagerInternal)
.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 82b89bb..91fd76e 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -164,7 +164,7 @@
assertArrayEquals(new int[]{-1, 10, 20, 30, 40},
mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux());
- // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
+ // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
@@ -236,7 +236,7 @@
assertArrayEquals(mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(),
HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE);
- // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
+ // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
diff --git a/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java
new file mode 100644
index 0000000..24fc348
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class HbmEventTest {
+ private long mStartTimeMillis;
+ private long mEndTimeMillis;
+ private HbmEvent mHbmEvent;
+
+ @Before
+ public void setUp() {
+ mStartTimeMillis = 10;
+ mEndTimeMillis = 20;
+ mHbmEvent = new HbmEvent(mStartTimeMillis, mEndTimeMillis);
+ }
+
+ @Test
+ public void getCorrectValues() {
+ assertEquals(mHbmEvent.getStartTimeMillis(), mStartTimeMillis);
+ assertEquals(mHbmEvent.getEndTimeMillis(), mEndTimeMillis);
+ }
+
+ @Test
+ public void toStringGeneratesExpectedString() {
+ String actualString = mHbmEvent.toString();
+ String expectedString = "HbmEvent: {startTimeMillis:" + mStartTimeMillis
+ + ", endTimeMillis: " + mEndTimeMillis + "}, total: "
+ + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]";
+ assertEquals(actualString, expectedString);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index a1e5ce7..2655c3f 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -96,6 +96,7 @@
private Binder mDisplayToken;
private String mDisplayUniqueId;
private Context mContextSpy;
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata;
@Rule
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@@ -118,6 +119,7 @@
mTestLooper = new TestLooper(mClock::now);
mDisplayToken = null;
mDisplayUniqueId = "unique_id";
+
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(resolver);
@@ -134,7 +136,8 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {},
+ null, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@@ -144,7 +147,8 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {},
+ null, mContextSpy);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -699,9 +703,12 @@
// Creates instance with standard initialization values.
private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) {
initHandler(clock);
+ if (mHighBrightnessModeMetadata == null) {
+ mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
+ }
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
- DEFAULT_HBM_DATA, null, () -> {}, mContextSpy);
+ DEFAULT_HBM_DATA, null, () -> {}, mHighBrightnessModeMetadata, mContextSpy);
}
private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
new file mode 100644
index 0000000..ede54e0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class HighBrightnessModeMetadataTest {
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata;
+
+ private long mRunningStartTimeMillis = -1;
+
+ @Before
+ public void setUp() {
+ mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
+ }
+
+ @Test
+ public void checkDefaultValues() {
+ assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(),
+ mRunningStartTimeMillis);
+ assertEquals(mHighBrightnessModeMetadata.getHbmEventQueue().size(), 0);
+ }
+
+ @Test
+ public void checkSetValues() {
+ mRunningStartTimeMillis = 10;
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(mRunningStartTimeMillis);
+ assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(),
+ mRunningStartTimeMillis);
+ HbmEvent expectedHbmEvent = new HbmEvent(10, 20);
+ mHighBrightnessModeMetadata.addHbmEvent(expectedHbmEvent);
+ HbmEvent actualHbmEvent = mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst();
+ assertEquals(expectedHbmEvent.toString(), actualHbmEvent.toString());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 5ef762b..a860387 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static android.view.Display.TYPE_EXTERNAL;
@@ -537,6 +538,11 @@
/* isOverrideActive= */false,
/* isInteractive= */true,
/* isBootCompleted= */true));
+ assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
+ INVALID_DEVICE_STATE,
+ /* isOverrideActive= */false,
+ /* isInteractive= */true,
+ /* isBootCompleted= */true));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java
index 57aa61a..e58b3e8 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java
@@ -65,7 +65,7 @@
@Test
public void setReasonDoesntSetIfModifierIsBeyondExtremes() {
- int extremeReason = 10;
+ int extremeReason = BrightnessReason.REASON_MAX + 1;
mBrightnessReason.setReason(extremeReason);
assertEquals(mBrightnessReason.getReason(), BrightnessReason.REASON_DOZE);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index cbeaf7b..d4ab794 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -16,18 +16,26 @@
package com.android.server.display.brightness;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManager;
import android.view.Display;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.display.BrightnessSetting;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
+import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
import org.junit.Before;
import org.junit.Test;
@@ -39,11 +47,16 @@
@RunWith(AndroidJUnit4.class)
public final class DisplayBrightnessControllerTest {
private static final int DISPLAY_ID = 1;
+ private static final float DEFAULT_BRIGHTNESS = 0.4f;
@Mock
private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
@Mock
private Context mContext;
+ @Mock
+ private BrightnessSetting mBrightnessSetting;
+ @Mock
+ private Runnable mOnBrightnessChangeRunnable;
private DisplayBrightnessController mDisplayBrightnessController;
@@ -58,11 +71,11 @@
}
};
mDisplayBrightnessController = new DisplayBrightnessController(mContext, injector,
- DISPLAY_ID);
+ DISPLAY_ID, DEFAULT_BRIGHTNESS, mBrightnessSetting, mOnBrightnessChangeRunnable);
}
@Test
- public void updateBrightnessWorksAsExpected() {
+ public void testUpdateBrightness() {
DisplayPowerRequest displayPowerRequest = mock(DisplayPowerRequest.class);
DisplayBrightnessStrategy displayBrightnessStrategy = mock(DisplayBrightnessStrategy.class);
int targetDisplayState = Display.STATE_DOZE;
@@ -70,6 +83,8 @@
targetDisplayState)).thenReturn(displayBrightnessStrategy);
mDisplayBrightnessController.updateBrightness(displayPowerRequest, targetDisplayState);
verify(displayBrightnessStrategy).updateBrightness(displayPowerRequest);
+ assertEquals(mDisplayBrightnessController.getCurrentDisplayBrightnessStrategyLocked(),
+ displayBrightnessStrategy);
}
@Test
@@ -77,4 +92,154 @@
mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig();
verify(mDisplayBrightnessStrategySelector).isAllowAutoBrightnessWhileDozingConfig();
}
+
+ @Test
+ public void setTemporaryBrightness() {
+ float temporaryBrightness = 0.4f;
+ TemporaryBrightnessStrategy temporaryBrightnessStrategy = mock(
+ TemporaryBrightnessStrategy.class);
+ when(mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()).thenReturn(
+ temporaryBrightnessStrategy);
+ mDisplayBrightnessController.setTemporaryBrightness(temporaryBrightness);
+ verify(temporaryBrightnessStrategy).setTemporaryScreenBrightness(temporaryBrightness);
+ }
+
+ @Test
+ public void setCurrentScreenBrightness() {
+ // Current Screen brightness is set as expected when a different value than the current
+ // is set
+ float currentScreenBrightness = 0.4f;
+ mDisplayBrightnessController.setCurrentScreenBrightness(currentScreenBrightness);
+ assertEquals(mDisplayBrightnessController.getCurrentBrightness(),
+ currentScreenBrightness, 0.0f);
+ verify(mOnBrightnessChangeRunnable).run();
+
+ // No change to the current screen brightness is same as the existing one
+ mDisplayBrightnessController.setCurrentScreenBrightness(currentScreenBrightness);
+ verifyNoMoreInteractions(mOnBrightnessChangeRunnable);
+ }
+
+ @Test
+ public void setPendingScreenBrightnessSetting() {
+ float pendingScreenBrightness = 0.4f;
+ mDisplayBrightnessController.setPendingScreenBrightness(pendingScreenBrightness);
+ assertEquals(mDisplayBrightnessController.getPendingScreenBrightness(),
+ pendingScreenBrightness, 0.0f);
+ }
+
+ @Test
+ public void updateUserSetScreenBrightness() {
+ // No brightness is set if the pending brightness is invalid
+ mDisplayBrightnessController.setPendingScreenBrightness(Float.NaN);
+ assertFalse(mDisplayBrightnessController.updateUserSetScreenBrightness());
+
+ // user set brightness is not set if the current and the pending brightness are same.
+ float currentBrightness = 0.4f;
+ TemporaryBrightnessStrategy temporaryBrightnessStrategy = mock(
+ TemporaryBrightnessStrategy.class);
+ when(mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()).thenReturn(
+ temporaryBrightnessStrategy);
+ mDisplayBrightnessController.setCurrentScreenBrightness(currentBrightness);
+ mDisplayBrightnessController.setPendingScreenBrightness(currentBrightness);
+ mDisplayBrightnessController.setTemporaryBrightness(currentBrightness);
+ assertFalse(mDisplayBrightnessController.updateUserSetScreenBrightness());
+ verify(temporaryBrightnessStrategy).setTemporaryScreenBrightness(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertEquals(mDisplayBrightnessController.getPendingScreenBrightness(),
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, 0.0f);
+
+ // user set brightness is set as expected
+ currentBrightness = 0.4f;
+ float pendingScreenBrightness = 0.3f;
+ float temporaryScreenBrightness = 0.2f;
+ mDisplayBrightnessController.setCurrentScreenBrightness(currentBrightness);
+ mDisplayBrightnessController.setPendingScreenBrightness(pendingScreenBrightness);
+ mDisplayBrightnessController.setTemporaryBrightness(temporaryScreenBrightness);
+ assertTrue(mDisplayBrightnessController.updateUserSetScreenBrightness());
+ assertEquals(mDisplayBrightnessController.getCurrentBrightness(),
+ pendingScreenBrightness, 0.0f);
+ assertEquals(mDisplayBrightnessController.getLastUserSetScreenBrightness(),
+ pendingScreenBrightness, 0.0f);
+ verify(mOnBrightnessChangeRunnable, times(2)).run();
+ verify(temporaryBrightnessStrategy, times(2))
+ .setTemporaryScreenBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertEquals(mDisplayBrightnessController.getPendingScreenBrightness(),
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, 0.0f);
+ }
+
+ @Test
+ public void registerBrightnessSettingChangeListener() {
+ BrightnessSetting.BrightnessSettingListener brightnessSettingListener = mock(
+ BrightnessSetting.BrightnessSettingListener.class);
+ mDisplayBrightnessController.registerBrightnessSettingChangeListener(
+ brightnessSettingListener);
+ verify(mBrightnessSetting).registerListener(brightnessSettingListener);
+ assertEquals(mDisplayBrightnessController.getBrightnessSettingListenerLocked(),
+ brightnessSettingListener);
+ }
+
+ @Test
+ public void getScreenBrightnessSetting() {
+ // getScreenBrightnessSetting returns the value relayed by BrightnessSetting, if the
+ // valid is valid and in range
+ float brightnessSetting = 0.2f;
+ when(mBrightnessSetting.getBrightness()).thenReturn(brightnessSetting);
+ assertEquals(mDisplayBrightnessController.getScreenBrightnessSetting(), brightnessSetting,
+ 0.0f);
+
+ // getScreenBrightnessSetting value is clamped if BrightnessSetting returns value beyond max
+ brightnessSetting = 1.1f;
+ when(mBrightnessSetting.getBrightness()).thenReturn(brightnessSetting);
+ assertEquals(mDisplayBrightnessController.getScreenBrightnessSetting(), 1.0f,
+ 0.0f);
+
+ // getScreenBrightnessSetting returns default value is BrightnessSetting returns invalid
+ // value.
+ brightnessSetting = Float.NaN;
+ when(mBrightnessSetting.getBrightness()).thenReturn(brightnessSetting);
+ assertEquals(mDisplayBrightnessController.getScreenBrightnessSetting(), DEFAULT_BRIGHTNESS,
+ 0.0f);
+ }
+
+ @Test
+ public void setBrightnessSetsInBrightnessSetting() {
+ float brightnessValue = 0.3f;
+ mDisplayBrightnessController.setBrightness(brightnessValue);
+ verify(mBrightnessSetting).setBrightness(brightnessValue);
+ }
+
+ @Test
+ public void updateScreenBrightnessSetting() {
+ // This interaction happens in the constructor itself
+ verify(mBrightnessSetting).getBrightness();
+
+ // Sets the appropriate value when valid, and not equal to the current brightness
+ float brightnessValue = 0.3f;
+ mDisplayBrightnessController.updateScreenBrightnessSetting(brightnessValue);
+ assertEquals(mDisplayBrightnessController.getCurrentBrightness(), brightnessValue,
+ 0.0f);
+ verify(mOnBrightnessChangeRunnable).run();
+ verify(mBrightnessSetting).setBrightness(brightnessValue);
+
+ // Does nothing if the value is invalid
+ mDisplayBrightnessController.updateScreenBrightnessSetting(Float.NaN);
+ verifyNoMoreInteractions(mOnBrightnessChangeRunnable, mBrightnessSetting);
+
+ // Does nothing if the value is same as the current brightness
+ brightnessValue = 0.2f;
+ mDisplayBrightnessController.setCurrentScreenBrightness(brightnessValue);
+ verify(mOnBrightnessChangeRunnable, times(2)).run();
+ mDisplayBrightnessController.updateScreenBrightnessSetting(brightnessValue);
+ verifyNoMoreInteractions(mOnBrightnessChangeRunnable, mBrightnessSetting);
+ }
+
+ @Test
+ public void stop() {
+ BrightnessSetting.BrightnessSettingListener brightnessSettingListener = mock(
+ BrightnessSetting.BrightnessSettingListener.class);
+ mDisplayBrightnessController.registerBrightnessSettingChangeListener(
+ brightnessSettingListener);
+ mDisplayBrightnessController.stop();
+ verify(mBrightnessSetting).unregisterListener(brightnessSettingListener);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index dcf217c..a9e616d 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -31,6 +31,7 @@
import com.android.internal.R;
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
@@ -61,6 +62,8 @@
@Mock
private InvalidBrightnessStrategy mInvalidBrightnessStrategy;
@Mock
+ private FollowerBrightnessStrategy mFollowerBrightnessStrategy;
+ @Mock
private Context mContext;
@Mock
private Resources mResources;
@@ -100,6 +103,11 @@
}
@Override
+ FollowerBrightnessStrategy getFollowerBrightnessStrategy(int displayId) {
+ return mFollowerBrightnessStrategy;
+ }
+
+ @Override
InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
return mInvalidBrightnessStrategy;
}
@@ -133,6 +141,7 @@
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
displayPowerRequest.screenBrightnessOverride = 0.4f;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
Display.STATE_ON), mOverrideBrightnessStrategy);
}
@@ -142,6 +151,7 @@
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
displayPowerRequest.screenBrightnessOverride = Float.NaN;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(0.3f);
assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
Display.STATE_ON), mTemporaryBrightnessStrategy);
@@ -152,6 +162,7 @@
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
displayPowerRequest.boostScreenBrightness = true;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
displayPowerRequest.screenBrightnessOverride = Float.NaN;
when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
@@ -163,8 +174,18 @@
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
DisplayManagerInternal.DisplayPowerRequest.class);
displayPowerRequest.screenBrightnessOverride = Float.NaN;
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
Display.STATE_ON), mInvalidBrightnessStrategy);
}
+
+ @Test
+ public void selectStrategySelectsFollowerStrategyWhenValid() {
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+ DisplayManagerInternal.DisplayPowerRequest.class);
+ when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(0.3f);
+ assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+ Display.STATE_ON), mFollowerBrightnessStrategy);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
index 431a239..c1de894 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
@@ -44,7 +44,7 @@
}
@Test
- public void updateBrightnessWorksAsExpectedWhenBoostBrightnessIsRequested() {
+ public void testUpdateBrightnessWhenBoostBrightnessIsRequested() {
DisplayManagerInternal.DisplayPowerRequest
displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
displayPowerRequest.boostScreenBrightness = true;
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
index 29652ff..76fa172 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
@@ -41,7 +41,7 @@
}
@Test
- public void updateBrightnessWorksAsExpectedWhenScreenDozeStateIsRequested() {
+ public void testUpdateBrightnessWhenScreenDozeStateIsRequested() {
DisplayPowerRequest displayPowerRequest = new DisplayPowerRequest();
float dozeScreenBrightness = 0.2f;
displayPowerRequest.dozeScreenBrightness = dozeScreenBrightness;
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
new file mode 100644
index 0000000..f20404e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FollowerBrightnessStrategyTest {
+ private FollowerBrightnessStrategy mFollowerBrightnessStrategy;
+
+ @Before
+ public void before() {
+ mFollowerBrightnessStrategy = new FollowerBrightnessStrategy(Display.DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testUpdateBrightness() {
+ DisplayManagerInternal.DisplayPowerRequest
+ displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+ float brightnessToFollow = 0.2f;
+ mFollowerBrightnessStrategy.setBrightnessToFollow(brightnessToFollow);
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_FOLLOWER);
+ DisplayBrightnessState expectedDisplayBrightnessState =
+ new DisplayBrightnessState.Builder()
+ .setBrightness(brightnessToFollow)
+ .setBrightnessReason(brightnessReason)
+ .setSdrBrightness(brightnessToFollow)
+ .build();
+ DisplayBrightnessState updatedDisplayBrightnessState =
+ mFollowerBrightnessStrategy.updateBrightness(displayPowerRequest);
+ assertEquals(expectedDisplayBrightnessState, updatedDisplayBrightnessState);
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index 4d89c28..2487b32b 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -43,7 +43,7 @@
}
@Test
- public void updateBrightnessWorksAsExpectedWhenScreenDozeStateIsRequested() {
+ public void testUpdateBrightnessWhenScreenDozeStateIsRequested() {
DisplayManagerInternal.DisplayPowerRequest
displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
float overrideBrightness = 0.2f;
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
index 0505475..353e92e 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
@@ -43,7 +43,7 @@
}
@Test
- public void updateBrightnessWorksAsExpectedWhenScreenOffDisplayState() {
+ public void testUpdateBrightnessWhenScreenOffDisplayState() {
DisplayPowerRequest displayPowerRequest = new DisplayPowerRequest();
BrightnessReason brightnessReason = new BrightnessReason();
brightnessReason.setReason(BrightnessReason.REASON_SCREEN_OFF);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
index b92aa9c..99679a3 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -43,7 +43,7 @@
}
@Test
- public void updateBrightnessWorksAsExpectedWhenTemporaryBrightnessIsSet() {
+ public void testUpdateBrightnessWhenTemporaryBrightnessIsSet() {
DisplayManagerInternal.DisplayPowerRequest
displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
float temporaryBrightness = 0.2f;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
index 93b151e..9f295b8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
@@ -175,7 +175,11 @@
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
index 4d8d25a..9c1b670 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
@@ -137,11 +137,17 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_PLAYBACK_1,
- true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_PLAYBACK_1)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
hdmiPortInfos[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_PLAYBACK_2,
- true, false, false);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_PLAYBACK_2)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index bb50a89..3bde665 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -112,7 +112,11 @@
public HdmiPortInfo[] nativeGetPortInfos() {
if (mHdmiPortInfo == null) {
mHdmiPortInfo = new HdmiPortInfo[1];
- mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
+ mHdmiPortInfo[0] = new HdmiPortInfo.Builder(1, 1, 0x1000)
+ .setCecSupported(true)
+ .setMhlSupported(true)
+ .setArcSupported(true)
+ .build();
}
return mHdmiPortInfo;
}
@@ -138,6 +142,14 @@
return isConnected == null ? false : isConnected;
}
+ @Override
+ public void nativeSetHpdSignalType(int signal, int portId) {}
+
+ @Override
+ public int nativeGetHpdSignalType(int portId) {
+ return Constants.HDMI_HPD_TYPE_PHYSICAL;
+ }
+
public void setPortConnectionStatus(int port, boolean connected) {
mPortConnectionStatus.put(port, connected);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index f27587e..e3d9558 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -118,7 +118,11 @@
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 90acc99..f5c0f2a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -197,17 +197,29 @@
mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnabled(true);
mHdmiPortInfo = new HdmiPortInfo[4];
mHdmiPortInfo[0] =
- new HdmiPortInfo(
- 0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS, true, false, false);
+ new HdmiPortInfo.Builder(0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[1] =
- new HdmiPortInfo(
- 2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS, true, false, false);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[2] =
- new HdmiPortInfo(
- 1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[3] =
- new HdmiPortInfo(
- 4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
+ new HdmiPortInfo.Builder(4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index dfab207..beba9c6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -150,7 +150,11 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
mHdmiControlService.initService();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 3796ce9..9c5c0d4 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -189,7 +189,11 @@
mLocalDevices.add(mHdmiLocalDevice);
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
mHdmiControlService.initService();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index cb1e78b..ccfc2b9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -193,10 +193,19 @@
mHdmiControlService.setEarcController(mHdmiEarcController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2];
- hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false, false);
+ hdmiPortInfos[0] = new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x1000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(false)
+ .build();
hdmiPortInfos[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true, true);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(true)
+ .setEarcSupported(true)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
index a82a79f..d341153 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
@@ -92,15 +92,35 @@
mHdmiPortInfo = new HdmiPortInfo[5];
mHdmiPortInfo[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x2100)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2200)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[2] =
- new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
+ new HdmiPortInfo.Builder(3, HdmiPortInfo.PORT_INPUT, 0x2000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[3] =
- new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
+ new HdmiPortInfo.Builder(4, HdmiPortInfo.PORT_INPUT, 0x3000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mHdmiPortInfo[4] =
- new HdmiPortInfo(5, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(5, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiCecNetwork.initPortInfo();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 8e5bb13..55e8b20 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -99,7 +99,11 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
mHdmiControlService.initService();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index cd6dfbf..8baad61 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -139,13 +139,33 @@
mLocalDevices.add(mPlaybackDeviceSpy);
mHdmiPortInfo = new HdmiPortInfo[4];
mHdmiPortInfo[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x2100)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(false)
+ .build();
mHdmiPortInfo[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false, false);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2200)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(false)
+ .build();
mHdmiPortInfo[2] =
- new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true, true);
+ new HdmiPortInfo.Builder(3, HdmiPortInfo.PORT_INPUT, 0x2000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(true)
+ .setEarcSupported(true)
+ .build();
mHdmiPortInfo[3] =
- new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false, false);
+ new HdmiPortInfo.Builder(4, HdmiPortInfo.PORT_INPUT, 0x3000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiControlServiceSpy.initService();
mPowerManager = new FakePowerManagerWrapper(mContextSpy);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index a623841..89743cd 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -102,9 +102,17 @@
mTestLooper.dispatchAll();
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[2];
hdmiPortInfo[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x1000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
hdmiPortInfo[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfo);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
index 4e8cf4a..5b1bdf6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -180,8 +180,11 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR,
- true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index 70f9e5c..c40cd0e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -102,9 +102,17 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2];
hdmiPortInfos[0] =
- new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false);
+ new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x1000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .build();
hdmiPortInfos[1] =
- new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true);
+ new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(true)
+ .build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mHdmiControlService.initService();
mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index f2e03aa..e871fc5 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -37,7 +37,6 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -165,18 +164,6 @@
awaitJobStart(DEFAULT_WAIT_TIMEOUT));
}
- @FlakyTest
- @Test
- public void testFeatureFlag() throws Exception {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.FORCED_APP_STANDBY_ENABLED, 0);
- scheduleAndAssertJobStarted();
- setAppOpsModeAllowed(false);
- mIActivityManager.makePackageIdle(TEST_APP_PACKAGE, UserHandle.USER_CURRENT);
- assertFalse("Job stopped even when feature flag was disabled",
- awaitJobStop(DEFAULT_WAIT_TIMEOUT, JobParameters.STOP_REASON_UNDEFINED));
- }
-
@After
public void tearDown() throws Exception {
final Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS);
@@ -187,8 +174,6 @@
Thread.sleep(500); // To avoid race with register in the next setUp
setAppOpsModeAllowed(true);
setPowerExemption(false);
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.FORCED_APP_STANDBY_ENABLED, 1);
}
private void setPowerExemption(boolean exempt) throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
index 2658af6..6f89ff0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -104,7 +104,7 @@
@Before
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getTargetContext();
- mDatabaseHelper = new RecoverableKeyStoreDbHelper(context);
+ mDatabaseHelper = new RecoverableKeyStoreDbHelper(context, 7);
mDatabase = SQLiteDatabase.create(null);
}
@@ -128,7 +128,7 @@
@Test
public void onUpgrade_beforeV2() throws Exception {
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 1,
- RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+ RecoverableKeyStoreDbHelper.DATABASE_VERSION_7);
checkAllColumns_latest();
}
@@ -136,7 +136,7 @@
public void onUpgrade_fromV2() throws Exception {
createV2Tables();
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2,
- RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+ RecoverableKeyStoreDbHelper.DATABASE_VERSION_7);
checkAllColumns_latest();
}
@@ -153,8 +153,7 @@
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3, /*newVersion=*/ 4);
checkAllColumns_v4();
- mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 4,
- RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+ mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 4, /*newVersion=*/ 7);
checkAllColumns_latest();
}
@@ -243,6 +242,14 @@
assertThat(
mDatabase.replace(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
.isGreaterThan(-1L);
+
+ // Bad guess counter was added when upgrading from v6 to v7
+ values = new ContentValues();
+ values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+ values.put(UserMetadataEntry.COLUMN_NAME_BAD_REMOTE_GUESS_COUNTER, 2);
+ assertThat(
+ mDatabase.replace(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+ .isGreaterThan(-1L);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 7a20af4..e223a97 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -67,7 +67,7 @@
public void setUp() {
Context context = InstrumentationRegistry.getTargetContext();
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
- mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
+ mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context, 7);
}
@After
@@ -309,24 +309,63 @@
int userId = 42;
int generationId = 110;
Long serialNumber = 10L;
+ int badGuessCounter = 3;
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId, badGuessCounter);
mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
+ assertEquals(badGuessCounter, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId));
assertEquals(generationId, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
}
@Test
+ public void getRemoteBadGuessCounter_returnsZeroAsDefaultValue() {
+ assertEquals(0, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(42));
+ }
+
+ @Test
+ public void getRemoteBadGuessCounter_returnsStoredValue() {
+ int userId = 42;
+ int userId2 = 44;
+ int badGuessCounter = 3;
+ int badGuessCounter2 = 4;
+
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId, badGuessCounter);
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId2, badGuessCounter2);
+
+ assertEquals(badGuessCounter, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId));
+ assertEquals(badGuessCounter2, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId2));
+ }
+
+ @Test
+ public void getBadRemoteGuessCounter_returnsStoredValue() {
+ int userId = 42;
+ int userId2 = 44;
+ int badGuessCounter = 3;
+ int badGuessCounter2 = 4;
+
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId, badGuessCounter);
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId2, badGuessCounter2);
+
+ assertEquals(badGuessCounter, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId));
+ assertEquals(badGuessCounter2, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId2));
+ }
+
+ @Test
public void setPlatformKeyGenerationId_keepsUserSerialNumber() {
int userId = 42;
int generationId = 110;
Long serialNumber = 10L;
+ int badGuessCounter = 3;
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
- mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
+ mRecoverableKeyStoreDb.setBadRemoteGuessCounter(userId, badGuessCounter);
assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
+ assertEquals(generationId, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
+ assertEquals(badGuessCounter, mRecoverableKeyStoreDb.getBadRemoteGuessCounter(userId));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorageTest.java
new file mode 100644
index 0000000..a1cf128
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RemoteLockscreenValidationSessionStorageTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.locksettings.recoverablekeystore.SecureBox;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteLockscreenValidationSessionStorageTest {
+ private static final int USER_ID = 0;
+ private static final int USER_ID_2 = 2;
+
+ RemoteLockscreenValidationSessionStorage mStorage;
+
+ @Before
+ public void setUp() {
+ mStorage = new RemoteLockscreenValidationSessionStorage();
+ }
+
+ @Test
+ public void get_noStoredSessions_returnsNull() {
+ assertThat(mStorage.get(USER_ID)).isNull();
+ }
+
+ @Test
+ public void startSession() {
+ mStorage.startSession(USER_ID);
+
+ assertThat(mStorage.get(USER_ID)).isNotNull();
+ assertThat(mStorage.get(USER_ID_2)).isNull();
+ }
+
+ @Test
+ public void finishSession_removesSessionFromStorage() {
+ mStorage.startSession(USER_ID);
+
+ mStorage.finishSession(USER_ID);
+
+ assertThat(mStorage.get(USER_ID)).isNull();
+ }
+
+ @Test
+ public void getLockscreenValidationCleanupTask() throws Exception {
+ long time11MinutesAgo = SystemClock.elapsedRealtime() - 11 * 60 * 1000;
+ long time2MinutesAgo = SystemClock.elapsedRealtime() - 2 * 60 * 1000;
+ mStorage.mSessionsByUserId.put(
+ USER_ID, mStorage.new LockscreenVerificationSession(
+ SecureBox.genKeyPair(), time11MinutesAgo));
+ mStorage.mSessionsByUserId.put(
+ USER_ID_2, mStorage.new LockscreenVerificationSession(
+ SecureBox.genKeyPair(), time2MinutesAgo));
+
+ mStorage.getLockscreenValidationCleanupTask().run();
+
+ assertThat(mStorage.get(USER_ID)).isNull();
+ assertThat(mStorage.get(USER_ID_2)).isNotNull();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index 26d0ddf..ade1bd4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -64,6 +64,8 @@
.setUseParentsContacts(false)
.setCrossProfileIntentFilterAccessControl(10)
.setCrossProfileIntentResolutionStrategy(0)
+ .setMediaSharedWithParent(false)
+ .setCredentialShareableWithParent(true)
.build();
final UserProperties actualProps = new UserProperties(defaultProps);
actualProps.setShowInLauncher(14);
@@ -72,6 +74,8 @@
actualProps.setUseParentsContacts(true);
actualProps.setCrossProfileIntentFilterAccessControl(20);
actualProps.setCrossProfileIntentResolutionStrategy(1);
+ actualProps.setMediaSharedWithParent(true);
+ actualProps.setCredentialShareableWithParent(false);
// Write the properties to xml.
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -111,6 +115,7 @@
.setStartWithParent(true)
.setShowInSettings(3452)
.setInheritDevicePolicy(1732)
+ .setMediaSharedWithParent(true)
.build();
final UserProperties orig = new UserProperties(defaultProps);
orig.setShowInLauncher(2841);
@@ -169,7 +174,10 @@
// Items with no permission requirements.
assertEqualGetterOrThrows(orig::getShowInLauncher, copy::getShowInLauncher, true);
-
+ assertEqualGetterOrThrows(orig::isMediaSharedWithParent,
+ copy::isMediaSharedWithParent, true);
+ assertEqualGetterOrThrows(orig::isCredentialShareableWithParent,
+ copy::isCredentialShareableWithParent, true);
}
/**
@@ -215,5 +223,9 @@
.isEqualTo(actual.getCrossProfileIntentFilterAccessControl());
assertThat(expected.getCrossProfileIntentResolutionStrategy())
.isEqualTo(actual.getCrossProfileIntentResolutionStrategy());
+ assertThat(expected.isMediaSharedWithParent())
+ .isEqualTo(actual.isMediaSharedWithParent());
+ assertThat(expected.isCredentialShareableWithParent())
+ .isEqualTo(actual.isCredentialShareableWithParent());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 928c6ef..702059d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -86,7 +86,9 @@
.setShowInLauncher(17)
.setUseParentsContacts(true)
.setCrossProfileIntentFilterAccessControl(10)
- .setCrossProfileIntentResolutionStrategy(1);
+ .setCrossProfileIntentResolutionStrategy(1)
+ .setMediaSharedWithParent(true)
+ .setCredentialShareableWithParent(false);
final UserTypeDetails type = new UserTypeDetails.Builder()
.setName("a.name")
.setEnabled(1)
@@ -148,6 +150,8 @@
.getCrossProfileIntentFilterAccessControl());
assertEquals(1, type.getDefaultUserPropertiesReference()
.getCrossProfileIntentResolutionStrategy());
+ assertTrue(type.getDefaultUserPropertiesReference().isMediaSharedWithParent());
+ assertFalse(type.getDefaultUserPropertiesReference().isCredentialShareableWithParent());
assertEquals(23, type.getBadgeLabel(0));
assertEquals(24, type.getBadgeLabel(1));
@@ -196,6 +200,8 @@
assertEquals(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT, props.getShowInLauncher());
assertEquals(UserProperties.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT,
props.getCrossProfileIntentResolutionStrategy());
+ assertFalse(props.isMediaSharedWithParent());
+ assertFalse(props.isCredentialShareableWithParent());
assertFalse(type.hasBadge());
}
@@ -279,7 +285,9 @@
.setStartWithParent(true)
.setUseParentsContacts(true)
.setCrossProfileIntentFilterAccessControl(10)
- .setCrossProfileIntentResolutionStrategy(1);
+ .setCrossProfileIntentResolutionStrategy(1)
+ .setMediaSharedWithParent(false)
+ .setCredentialShareableWithParent(true);
final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
builders.put(userTypeAosp1, new UserTypeDetails.Builder()
.setName(userTypeAosp1)
@@ -312,6 +320,9 @@
assertTrue(aospType.getDefaultUserPropertiesReference().getStartWithParent());
assertTrue(aospType.getDefaultUserPropertiesReference()
.getUseParentsContacts());
+ assertFalse(aospType.getDefaultUserPropertiesReference().isMediaSharedWithParent());
+ assertTrue(aospType.getDefaultUserPropertiesReference()
+ .isCredentialShareableWithParent());
// userTypeAosp2 should be modified.
aospType = builders.get(userTypeAosp2).createUserTypeDetails();
@@ -348,6 +359,9 @@
assertFalse(aospType.getDefaultUserPropertiesReference().getStartWithParent());
assertFalse(aospType.getDefaultUserPropertiesReference()
.getUseParentsContacts());
+ assertTrue(aospType.getDefaultUserPropertiesReference().isMediaSharedWithParent());
+ assertFalse(aospType.getDefaultUserPropertiesReference()
+ .isCredentialShareableWithParent());
// userTypeOem1 should be created.
UserTypeDetails.Builder customType = builders.get(userTypeOem1);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 1305e07..ac5bcff 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertThrows;
@@ -189,6 +188,10 @@
cloneUserProperties::getCrossProfileIntentFilterAccessControl);
assertThrows(SecurityException.class,
cloneUserProperties::getCrossProfileIntentResolutionStrategy);
+ assertThat(typeProps.isMediaSharedWithParent())
+ .isEqualTo(cloneUserProperties.isMediaSharedWithParent());
+ assertThat(typeProps.isCredentialShareableWithParent())
+ .isEqualTo(cloneUserProperties.isCredentialShareableWithParent());
// Verify clone user parent
assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
@@ -834,11 +837,13 @@
// provided that the test caller has the necessary permissions.
assertThat(userProps.getShowInLauncher()).isEqualTo(typeProps.getShowInLauncher());
assertThat(userProps.getShowInSettings()).isEqualTo(typeProps.getShowInSettings());
- assertFalse(userProps.getUseParentsContacts());
+ assertThat(userProps.getUseParentsContacts()).isFalse();
assertThrows(SecurityException.class, userProps::getCrossProfileIntentFilterAccessControl);
assertThrows(SecurityException.class, userProps::getCrossProfileIntentResolutionStrategy);
assertThrows(SecurityException.class, userProps::getStartWithParent);
assertThrows(SecurityException.class, userProps::getInheritDevicePolicy);
+ assertThat(userProps.isMediaSharedWithParent()).isFalse();
+ assertThat(userProps.isCredentialShareableWithParent()).isTrue();
}
// Make sure only max managed profiles can be created
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
new file mode 100644
index 0000000..0be678a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.pm.VersionedPackage;
+import android.util.Log;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.SystemConfig;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Scanner;
+
+@RunWith(AndroidJUnit4.class)
+public class RollbackPackageHealthObserverTest {
+ private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
+
+ private SystemConfig mSysConfig;
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setup() {
+ mSysConfig = new SystemConfigTestClass();
+ }
+
+ /**
+ * Subclass of SystemConfig without running the constructor.
+ */
+ private class SystemConfigTestClass extends SystemConfig {
+ SystemConfigTestClass() {
+ super(false);
+ }
+ }
+
+ /**
+ * Test that isAutomaticRollbackDenied works correctly when packages that are not
+ * denied are sent.
+ */
+ @Test
+ public void isRollbackAllowedTest_false() throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <automatic-rollback-denylisted-app package=\"com.android.vending\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents);
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig,
+ new VersionedPackage("com.test.package", 1))).isEqualTo(false);
+ }
+
+ /**
+ * Test that isAutomaticRollbackDenied works correctly when packages that are
+ * denied are sent.
+ */
+ @Test
+ public void isRollbackAllowedTest_true() throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <automatic-rollback-denylisted-app package=\"com.android.vending\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents);
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig,
+ new VersionedPackage("com.android.vending", 1))).isEqualTo(true);
+ }
+
+ /**
+ * Test that isAutomaticRollbackDenied works correctly when no config is present
+ */
+ @Test
+ public void isRollbackAllowedTest_noConfig() throws IOException {
+ final File folder = createTempSubfolder("folder");
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig,
+ new VersionedPackage("com.android.vending", 1))).isEqualTo(false);
+ }
+
+ /**
+ * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
+ *
+ * @param folder pre-existing subdirectory of mTemporaryFolder to put the file
+ * @param fileName name of the file (e.g. filename.xml) to create
+ * @param contents contents to write to the file
+ * @return the newly created file
+ */
+ private File createTempFile(File folder, String fileName, String contents)
+ throws IOException {
+ File file = new File(folder, fileName);
+ BufferedWriter bw = new BufferedWriter(new FileWriter(file));
+ bw.write(contents);
+ bw.close();
+
+ // Print to logcat for test debugging.
+ Log.d(LOG_TAG, "Contents of file " + file.getAbsolutePath());
+ Scanner input = new Scanner(file);
+ while (input.hasNextLine()) {
+ Log.d(LOG_TAG, input.nextLine());
+ }
+
+ return file;
+ }
+
+ private void readPermissions(File libraryDir, int permissionFlag) {
+ final XmlPullParser parser = Xml.newPullParser();
+ mSysConfig.readPermissions(parser, libraryDir, permissionFlag);
+ }
+
+ /**
+ * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
+ *
+ * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed
+ * @return the folder
+ */
+ private File createTempSubfolder(String folderName)
+ throws IOException {
+ File folder = new File(mTemporaryFolder.getRoot(), folderName);
+ folder.mkdirs();
+ return folder;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index d073f5b..aca96ad 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -595,6 +595,56 @@
}
/**
+ * Test that getRollbackDenylistedPackages works correctly for the tag:
+ * {@code automatic-rollback-denylisted-app}.
+ */
+ @Test
+ public void automaticRollbackDeny_vending() throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <automatic-rollback-denylisted-app package=\"com.android.vending\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents);
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages())
+ .containsExactly("com.android.vending");
+ }
+
+ /**
+ * Test that getRollbackDenylistedPackages works correctly for the tag:
+ * {@code automatic-rollback-denylisted-app} without any packages.
+ */
+ @Test
+ public void automaticRollbackDeny_empty() throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <automatic-rollback-denylisted-app />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents);
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages()).isEmpty();
+ }
+
+ /**
+ * Test that getRollbackDenylistedPackages works correctly for the tag:
+ * {@code automatic-rollback-denylisted-app} without the corresponding config.
+ */
+ @Test
+ public void automaticRollbackDeny_noConfig() throws IOException {
+ final File folder = createTempSubfolder("folder");
+
+ readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages()).isEmpty();
+ }
+
+ /**
* Tests that readPermissions works correctly for the tag: {@code update-ownership}.
*/
@Test
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index 50040b7..704b06b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -48,17 +48,17 @@
}
@Override
- public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
+ public void suggestTelephonyTime(TelephonyTimeSuggestion suggestion) {
}
@Override
- public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion,
+ public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion suggestion,
boolean bypassUserPolicyChecks) {
return true;
}
@Override
- public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+ public void suggestNetworkTime(NetworkTimeSuggestion suggestion) {
}
@Override
@@ -71,11 +71,11 @@
}
@Override
- public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
+ public void suggestGnssTime(GnssTimeSuggestion suggestion) {
}
@Override
- public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
+ public void suggestExternalTime(ExternalTimeSuggestion suggestion) {
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 1c014d1..590aba9 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -67,18 +67,17 @@
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import android.os.HandlerThread;
import android.service.timezone.TimeZoneProviderStatus;
import com.android.server.SystemTimeZone.TimeZoneConfidence;
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -208,8 +207,6 @@
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeEnvironment mFakeEnvironment;
- private HandlerThread mHandlerThread;
- private TestHandler mTestHandler;
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
@@ -220,18 +217,8 @@
mFakeServiceConfigAccessorSpy.initializeCurrentUserConfiguration(
CONFIG_AUTO_DISABLED_GEO_DISABLED);
- // Create a thread + handler for processing the work that the strategy posts.
- mHandlerThread = new HandlerThread("TimeZoneDetectorStrategyImplTest");
- mHandlerThread.start();
- mTestHandler = new TestHandler(mHandlerThread.getLooper());
mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(
- mFakeServiceConfigAccessorSpy, mTestHandler, mFakeEnvironment);
- }
-
- @After
- public void tearDown() throws Exception {
- mHandlerThread.quit();
- mHandlerThread.join();
+ mFakeServiceConfigAccessorSpy, mFakeEnvironment);
}
@Test
@@ -1723,6 +1710,7 @@
private final TestState<String> mTimeZoneId = new TestState<>();
private final TestState<Integer> mTimeZoneConfidence = new TestState<>();
+ private final List<Runnable> mAsyncRunnables = new ArrayList<>();
private @ElapsedRealtimeLong long mElapsedRealtimeMillis;
FakeEnvironment() {
@@ -1795,12 +1783,24 @@
public void dumpDebugLog(PrintWriter printWriter) {
// No-op for tests
}
+
+ @Override
+ public void runAsync(Runnable runnable) {
+ mAsyncRunnables.add(runnable);
+ }
+
+ public void runAsyncRunnables() {
+ for (Runnable runnable : mAsyncRunnables) {
+ runnable.run();
+ }
+ mAsyncRunnables.clear();
+ }
}
private void assertStateChangeNotificationsSent(
TestStateChangeListener stateChangeListener, int expectedCount) {
- // State change notifications are asynchronous, so we have to wait.
- mTestHandler.waitForMessagesToBeProcessed();
+ // The fake environment needs to be told to run posted work.
+ mFakeEnvironment.runAsyncRunnables();
stateChangeListener.assertNotificationsReceivedAndReset(expectedCount);
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index dcf1b35..9570ff6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -87,6 +87,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.hardware.display.DisplayManager;
+import android.os.BatteryStats;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -119,6 +120,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -249,6 +251,8 @@
.setLong("elapsed_threshold_rare", RARE_THRESHOLD)
.setLong("elapsed_threshold_restricted", RESTRICTED_THRESHOLD);
DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener;
+ String mExpectedNoteEventPackage = null;
+ int mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
MyInjector(Context context, Looper looper) {
super(context, looper);
@@ -320,6 +324,9 @@
@Override
void noteEvent(int event, String packageName, int uid) throws RemoteException {
+ if (Objects.equals(mExpectedNoteEventPackage, packageName)) {
+ mLastNoteEvent = event;
+ }
}
@Override
@@ -2103,6 +2110,50 @@
assertBucket(STANDBY_BUCKET_FREQUENT, PACKAGE_BACKGROUND_LOCATION);
}
+ @Test
+ public void testBatteryStatsNoteEvent() throws Exception {
+ mInjector.mExpectedNoteEventPackage = PACKAGE_1;
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
+
+ // Since we're staying on the PACKAGE_ACTIVE side, noteEvent shouldn't be called.
+ // Reset the last event to confirm the method isn't called.
+ mInjector.mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_NONE, mInjector.mLastNoteEvent);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
+
+ // Since we're staying on the PACKAGE_ACTIVE side, noteEvent shouldn't be called.
+ // Reset the last event to confirm the method isn't called.
+ mInjector.mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_NONE, mInjector.mLastNoteEvent);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_EXEMPTED,
+ REASON_MAIN_FORCED_BY_USER);
+ assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
+ }
+
private String getAdminAppsStr(int userId) {
return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/ConversionUtilTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/ConversionUtilTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/ConversionUtilTest.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/ConversionUtilTest.java
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/OWNERS
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java
rename to services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index fd1ca68..a76b82b 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -407,7 +407,7 @@
void assertShowRecentApps() {
waitForIdle();
- verify(mStatusBarManagerInternal).showRecentApps(anyBoolean(), anyBoolean());
+ verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
}
void assertSwitchKeyboardLayout() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1deb58e..d1ab541 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -113,6 +113,7 @@
import com.android.server.wm.utils.MockTracker;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -754,6 +755,7 @@
* start the background activity.
*/
@Test
+ @Ignore("b/266015587")
public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() {
doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 5e087f0..791d6f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -28,21 +28,36 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import android.annotation.Nullable;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
+import android.content.res.Resources;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.RoundedCorner;
+import android.view.RoundedCorners;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.Before;
@@ -61,6 +76,14 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class LetterboxUiControllerTest extends WindowTestsBase {
+ private static final int TASKBAR_COLLAPSED_HEIGHT = 10;
+ private static final int TASKBAR_EXPANDED_HEIGHT = 20;
+ private static final int SCREEN_WIDTH = 200;
+ private static final int SCREEN_HEIGHT = 100;
+ private static final Rect TASKBAR_COLLAPSED_BOUNDS = new Rect(0,
+ SCREEN_HEIGHT - TASKBAR_COLLAPSED_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT);
+ private static final Rect TASKBAR_EXPANDED_BOUNDS = new Rect(0,
+ SCREEN_HEIGHT - TASKBAR_EXPANDED_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT);
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -69,6 +92,7 @@
private DisplayContent mDisplayContent;
private LetterboxUiController mController;
private LetterboxConfiguration mLetterboxConfiguration;
+ private final Rect mLetterboxedPortraitTaskBounds = new Rect();
@Before
public void setUp() throws Exception {
@@ -308,6 +332,165 @@
assertTrue(mController.shouldForceRotateForCameraCompat());
}
+ @Test
+ public void testGetCropBoundsIfNeeded_noCrop() {
+ final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
+
+ // Do not apply crop if taskbar is collapsed
+ taskbar.setFrame(TASKBAR_COLLAPSED_BOUNDS);
+ assertNull(mController.getExpandedTaskbarOrNull(mainWindow));
+
+ mLetterboxedPortraitTaskBounds.set(SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4,
+ SCREEN_WIDTH - SCREEN_WIDTH / 4, SCREEN_HEIGHT - SCREEN_HEIGHT / 4);
+
+ final Rect noCrop = mController.getCropBoundsIfNeeded(mainWindow);
+ assertNotEquals(null, noCrop);
+ assertEquals(0, noCrop.left);
+ assertEquals(0, noCrop.top);
+ assertEquals(mLetterboxedPortraitTaskBounds.width(), noCrop.right);
+ assertEquals(mLetterboxedPortraitTaskBounds.height(), noCrop.bottom);
+ }
+
+ @Test
+ public void testGetCropBoundsIfNeeded_appliesCrop() {
+ final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
+
+ // Apply crop if taskbar is expanded
+ taskbar.setFrame(TASKBAR_EXPANDED_BOUNDS);
+ assertNotNull(mController.getExpandedTaskbarOrNull(mainWindow));
+
+ mLetterboxedPortraitTaskBounds.set(SCREEN_WIDTH / 4, 0, SCREEN_WIDTH - SCREEN_WIDTH / 4,
+ SCREEN_HEIGHT);
+
+ final Rect crop = mController.getCropBoundsIfNeeded(mainWindow);
+ assertNotEquals(null, crop);
+ assertEquals(0, crop.left);
+ assertEquals(0, crop.top);
+ assertEquals(mLetterboxedPortraitTaskBounds.width(), crop.right);
+ assertEquals(mLetterboxedPortraitTaskBounds.height() - TASKBAR_EXPANDED_HEIGHT,
+ crop.bottom);
+ }
+
+ @Test
+ public void testGetCropBoundsIfNeeded_appliesCropWithSizeCompatScaling() {
+ final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
+ final float scaling = 2.0f;
+
+ // Apply crop if taskbar is expanded
+ taskbar.setFrame(TASKBAR_EXPANDED_BOUNDS);
+ assertNotNull(mController.getExpandedTaskbarOrNull(mainWindow));
+ // With SizeCompat scaling
+ doReturn(true).when(mActivity).inSizeCompatMode();
+ mainWindow.mInvGlobalScale = scaling;
+
+ mLetterboxedPortraitTaskBounds.set(SCREEN_WIDTH / 4, 0, SCREEN_WIDTH - SCREEN_WIDTH / 4,
+ SCREEN_HEIGHT);
+
+ final int appWidth = mLetterboxedPortraitTaskBounds.width();
+ final int appHeight = mLetterboxedPortraitTaskBounds.height();
+
+ final Rect crop = mController.getCropBoundsIfNeeded(mainWindow);
+ assertNotEquals(null, crop);
+ assertEquals(0, crop.left);
+ assertEquals(0, crop.top);
+ assertEquals((int) (appWidth * scaling), crop.right);
+ assertEquals((int) ((appHeight - TASKBAR_EXPANDED_HEIGHT) * scaling), crop.bottom);
+ }
+
+ @Test
+ public void testGetRoundedCornersRadius_withRoundedCornersFromInsets() {
+ final float invGlobalScale = 0.5f;
+ final int expectedRadius = 7;
+ final int configurationRadius = 15;
+
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(/*taskbar=*/ null);
+ mainWindow.mInvGlobalScale = invGlobalScale;
+ final InsetsState insets = mainWindow.getInsetsState();
+
+ RoundedCorners roundedCorners = new RoundedCorners(
+ /*topLeft=*/ null,
+ /*topRight=*/ null,
+ /*bottomRight=*/ new RoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT,
+ configurationRadius, /*centerX=*/ 1, /*centerY=*/ 1),
+ /*bottomLeft=*/ new RoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT,
+ configurationRadius * 2 /*2 is to test selection of the min radius*/,
+ /*centerX=*/ 1, /*centerY=*/ 1)
+ );
+ doReturn(roundedCorners).when(insets).getRoundedCorners();
+ mLetterboxConfiguration.setLetterboxActivityCornersRadius(-1);
+
+ assertEquals(expectedRadius, mController.getRoundedCornersRadius(mainWindow));
+ }
+
+ @Test
+ public void testGetRoundedCornersRadius_withLetterboxActivityCornersRadius() {
+ final float invGlobalScale = 0.5f;
+ final int expectedRadius = 7;
+ final int configurationRadius = 15;
+
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(/*taskbar=*/ null);
+ mainWindow.mInvGlobalScale = invGlobalScale;
+ mLetterboxConfiguration.setLetterboxActivityCornersRadius(configurationRadius);
+
+ assertEquals(expectedRadius, mController.getRoundedCornersRadius(mainWindow));
+
+ }
+
+ @Test
+ public void testGetRoundedCornersRadius_noScalingApplied() {
+ final int configurationRadius = 15;
+
+ final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(/*taskbar=*/ null);
+ mLetterboxConfiguration.setLetterboxActivityCornersRadius(configurationRadius);
+
+ mainWindow.mInvGlobalScale = -1f;
+ assertEquals(configurationRadius, mController.getRoundedCornersRadius(mainWindow));
+
+ mainWindow.mInvGlobalScale = 0f;
+ assertEquals(configurationRadius, mController.getRoundedCornersRadius(mainWindow));
+
+ mainWindow.mInvGlobalScale = 1f;
+ assertEquals(configurationRadius, mController.getRoundedCornersRadius(mainWindow));
+ }
+
+ private WindowState mockForGetCropBoundsAndRoundedCorners(@Nullable InsetsSource taskbar) {
+ final WindowState mainWindow = mock(WindowState.class);
+ final InsetsState insets = mock(InsetsState.class);
+ final Resources resources = mWm.mContext.getResources();
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
+
+ mainWindow.mInvGlobalScale = 1f;
+ spyOn(resources);
+ spyOn(mActivity);
+
+ if (taskbar != null) {
+ taskbar.setVisible(true);
+ doReturn(taskbar).when(insets).peekSource(taskbar.getType());
+ }
+ doReturn(mLetterboxedPortraitTaskBounds).when(mActivity).getBounds();
+ doReturn(true).when(mActivity).isVisible();
+ doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+ doReturn(insets).when(mainWindow).getInsetsState();
+ doReturn(attrs).when(mainWindow).getAttrs();
+ doReturn(true).when(mainWindow).isDrawn();
+ doReturn(false).when(mainWindow).isLetterboxedForDisplayCutout();
+ doReturn(true).when(mainWindow).areAppWindowBoundsLetterboxed();
+ doReturn(true).when(mLetterboxConfiguration).isLetterboxActivityCornersRounded();
+ doReturn(TASKBAR_EXPANDED_HEIGHT).when(resources).getDimensionPixelSize(
+ R.dimen.taskbar_frame_height);
+
+ // Need to reinitialise due to the change in resources getDimensionPixelSize output.
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ return mainWindow;
+ }
+
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
/* className */ "");
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 3b7b5eb..7e150e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -2603,6 +2603,133 @@
}
@Test
+ public void testIsHorizontalReachabilityEnabled_splitScreen_false() {
+ mAtm.mDevEnableNonResizableMultiWindow = true;
+ setUpDisplaySizeWithApp(2800, 1000);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+
+ // Unresizable portrait-only activity.
+ prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, 1400, 1000);
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // Horizontal reachability is disabled because the app is in split screen.
+ assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+ }
+
+ @Test
+ public void testIsVerticalReachabilityEnabled_splitScreen_false() {
+ mAtm.mDevEnableNonResizableMultiWindow = true;
+ setUpDisplaySizeWithApp(1000, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+
+ // Unresizable landscape-only activity.
+ prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, 1000, 1400);
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // Vertical reachability is disabled because the app is in split screen.
+ assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+ }
+
+ @Test
+ public void testIsVerticalReachabilityEnabled_doesNotMatchParentWidth_false() {
+ setUpDisplaySizeWithApp(1000, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+
+ // Unresizable landscape-only activity.
+ prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Activity now in size compat mode.
+ assertTrue(mActivity.inSizeCompatMode());
+
+ // Vertical reachability is disabled because the app does not match parent width
+ assertNotEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds()
+ .width());
+ assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+ }
+
+ @Test
+ public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() {
+ setUpDisplaySizeWithApp(2800, 1000);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+
+ // Unresizable portrait-only activity.
+ prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Activity now in size compat mode.
+ assertTrue(mActivity.inSizeCompatMode());
+
+ // Horizontal reachability is disabled because the app does not match parent height
+ assertNotEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds()
+ .height());
+ assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+ }
+
+ @Test
+ public void testIsHorizontalReachabilityEnabled_inSizeCompatMode_matchesParentHeight_true() {
+ setUpDisplaySizeWithApp(1800, 2200);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+
+ // Unresizable portrait-only activity.
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Activity now in size compat mode.
+ assertTrue(mActivity.inSizeCompatMode());
+
+ // Horizontal reachability is enabled because the app matches parent height
+ assertEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds()
+ .height());
+ assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+ }
+
+ @Test
+ public void testIsVerticalReachabilityEnabled_inSizeCompatMode_matchesParentWidth_true() {
+ setUpDisplaySizeWithApp(2200, 1800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+
+ // Unresizable landscape-only activity.
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Activity now in size compat mode.
+ assertTrue(mActivity.inSizeCompatMode());
+
+ // Vertical reachability is enabled because the app matches parent width
+ assertEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds().width());
+ assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+ }
+
+ @Test
public void testLetterboxDetailsForStatusBar_noLetterbox() {
setUpDisplaySizeWithApp(2800, 1000);
addStatusBar(mActivity.mDisplayContent);
@@ -2711,7 +2838,7 @@
mActivity.mRootWindowContainer.performSurfacePlacement();
final ArgumentCaptor<Rect> cropCapturer = ArgumentCaptor.forClass(Rect.class);
- verify(mTransaction, times(2)).setWindowCrop(
+ verify(mTransaction, times(2)).setCrop(
eq(w1.getSurfaceControl()),
cropCapturer.capture()
);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index d31ae6a..83be4f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static android.view.Surface.ROTATION_0;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -78,6 +79,12 @@
final InputMonitor inputMonitor = getInputMonitor();
spyOn(inputMonitor);
doNothing().when(inputMonitor).resumeDispatchingLw(any());
+
+ // For devices that set the sysprop ro.bootanim.set_orientation_<display_id>
+ // See DisplayRotation#readDefaultDisplayRotation for context.
+ // Without that, meaning of height and width in context of the tests can be swapped if
+ // the default rotation is 90 or 270.
+ displayRotation.setRotation(ROTATION_0);
}
public static class Builder {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
index 3163820..20f03d8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.usage;
+import android.annotation.UserIdInt;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -35,65 +36,71 @@
public class UsageStatsIdleService extends JobService {
/**
- * Base job ID for the pruning job - must be unique within the system server uid.
+ * Namespace for prune job
*/
- private static final int PRUNE_JOB_ID = 546357475;
+ private static final String PRUNE_JOB_NS = "usagestats_prune";
+
/**
- * Job ID for the update mappings job - must be unique within the system server uid.
- * Incrementing PRUNE_JOB_ID by 21475 (MAX_USER_ID) to ensure there is no overlap in job ids.
+ * Namespace for update mappings job
*/
- private static final int UPDATE_MAPPINGS_JOB_ID = 546378950;
+ private static final String UPDATE_MAPPINGS_JOB_NS = "usagestats_mapping";
private static final String USER_ID_KEY = "user_id";
- static void scheduleJob(Context context, int userId) {
- final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ /** Schedule a prune job */
+ static void schedulePruneJob(Context context, @UserIdInt int userId) {
final ComponentName component = new ComponentName(context.getPackageName(),
UsageStatsIdleService.class.getName());
final PersistableBundle bundle = new PersistableBundle();
bundle.putInt(USER_ID_KEY, userId);
- final JobInfo pruneJob = new JobInfo.Builder(userJobId, component)
+ final JobInfo pruneJob = new JobInfo.Builder(userId, component)
.setRequiresDeviceIdle(true)
.setExtras(bundle)
.setPersisted(true)
.build();
- scheduleJobInternal(context, pruneJob, userJobId);
+ scheduleJobInternal(context, pruneJob, PRUNE_JOB_NS, userId);
}
- static void scheduleUpdateMappingsJob(Context context) {
+ static void scheduleUpdateMappingsJob(Context context, @UserIdInt int userId) {
final ComponentName component = new ComponentName(context.getPackageName(),
UsageStatsIdleService.class.getName());
- final JobInfo updateMappingsJob = new JobInfo.Builder(UPDATE_MAPPINGS_JOB_ID, component)
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putInt(USER_ID_KEY, userId);
+ final JobInfo updateMappingsJob = new JobInfo.Builder(userId, component)
.setPersisted(true)
.setMinimumLatency(TimeUnit.DAYS.toMillis(1))
.setOverrideDeadline(TimeUnit.DAYS.toMillis(2))
+ .setExtras(bundle)
.build();
- scheduleJobInternal(context, updateMappingsJob, UPDATE_MAPPINGS_JOB_ID);
+ scheduleJobInternal(context, updateMappingsJob, UPDATE_MAPPINGS_JOB_NS, userId);
}
- private static void scheduleJobInternal(Context context, JobInfo pruneJob, int jobId) {
- final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
- final JobInfo pendingPruneJob = jobScheduler.getPendingJob(jobId);
- // only schedule a new prune job if one doesn't exist already for this user
- if (!pruneJob.equals(pendingPruneJob)) {
- jobScheduler.cancel(jobId); // cancel any previously scheduled prune job
- jobScheduler.schedule(pruneJob);
+ private static void scheduleJobInternal(Context context, JobInfo jobInfo,
+ String namespace, int jobId) {
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ jobScheduler = jobScheduler.forNamespace(namespace);
+ final JobInfo pendingJob = jobScheduler.getPendingJob(jobId);
+ // only schedule a new job if one doesn't exist already for this user
+ if (!jobInfo.equals(pendingJob)) {
+ jobScheduler.cancel(jobId); // cancel any previously scheduled job
+ jobScheduler.schedule(jobInfo);
}
}
- static void cancelJob(Context context, int userId) {
- cancelJobInternal(context, PRUNE_JOB_ID + userId);
+ static void cancelPruneJob(Context context, @UserIdInt int userId) {
+ cancelJobInternal(context, PRUNE_JOB_NS, userId);
}
- static void cancelUpdateMappingsJob(Context context) {
- cancelJobInternal(context, UPDATE_MAPPINGS_JOB_ID);
+ static void cancelUpdateMappingsJob(Context context, @UserIdInt int userId) {
+ cancelJobInternal(context, UPDATE_MAPPINGS_JOB_NS, userId);
}
- private static void cancelJobInternal(Context context, int jobId) {
- final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ private static void cancelJobInternal(Context context, String namespace, int jobId) {
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
if (jobScheduler != null) {
+ jobScheduler = jobScheduler.forNamespace(namespace);
jobScheduler.cancel(jobId);
}
}
@@ -102,15 +109,19 @@
public boolean onStartJob(JobParameters params) {
final PersistableBundle bundle = params.getExtras();
final int userId = bundle.getInt(USER_ID_KEY, -1);
- if (userId == -1 && params.getJobId() != UPDATE_MAPPINGS_JOB_ID) {
+
+ if (userId == -1) { // legacy job
return false;
}
+ // Do async
AsyncTask.execute(() -> {
final UsageStatsManagerInternal usageStatsManagerInternal = LocalServices.getService(
UsageStatsManagerInternal.class);
- if (params.getJobId() == UPDATE_MAPPINGS_JOB_ID) {
- final boolean jobFinished = usageStatsManagerInternal.updatePackageMappingsData();
+ final String jobNs = params.getJobNamespace();
+ if (UPDATE_MAPPINGS_JOB_NS.equals(jobNs)) {
+ final boolean jobFinished =
+ usageStatsManagerInternal.updatePackageMappingsData(userId);
jobFinished(params, !jobFinished); // reschedule if data was not updated
} else {
final boolean jobFinished =
@@ -118,6 +129,8 @@
jobFinished(params, !jobFinished); // reschedule if data was not pruned
}
});
+
+ // Job is running asynchronously
return true;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b3a1f2b..7ff5b4a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -433,11 +433,9 @@
private void onUserUnlocked(int userId) {
// fetch the installed packages outside the lock so it doesn't block package manager.
final HashMap<String, Long> installedPackages = getInstalledPackages(userId);
- // delay updating of package mappings for user 0 since their data is not likely to be stale.
- // this also makes it less likely for restored data to be erased on unexpected reboots.
- if (userId == UserHandle.USER_SYSTEM) {
- UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
- }
+
+ UsageStatsIdleService.scheduleUpdateMappingsJob(getContext(), userId);
+
final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId));
synchronized (mLock) {
// This should be safe to add this early. Other than reportEventOrAddToQueue and
@@ -1261,8 +1259,8 @@
}
mAppStandby.onUserRemoved(userId);
// Cancel any scheduled jobs for this user since the user is being removed.
- UsageStatsIdleService.cancelJob(getContext(), userId);
- UsageStatsIdleService.cancelUpdateMappingsJob(getContext());
+ UsageStatsIdleService.cancelPruneJob(getContext(), userId);
+ UsageStatsIdleService.cancelUpdateMappingsJob(getContext(), userId);
}
/**
@@ -1300,7 +1298,7 @@
// Schedule a job to prune any data related to this package.
if (tokenRemoved != PackagesTokenData.UNASSIGNED_TOKEN) {
- UsageStatsIdleService.scheduleJob(getContext(), userId);
+ UsageStatsIdleService.schedulePruneJob(getContext(), userId);
}
}
@@ -1325,19 +1323,19 @@
/**
* Called by the Binder stub.
*/
- private boolean updatePackageMappingsData() {
+ private boolean updatePackageMappingsData(@UserIdInt int userId) {
// don't update the mappings if a profile user is defined
- if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) {
+ if (!shouldDeleteObsoleteData(UserHandle.of(userId))) {
return true; // return true so job scheduler doesn't reschedule the job
}
// fetch the installed packages outside the lock so it doesn't block package manager.
- final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
+ final HashMap<String, Long> installedPkgs = getInstalledPackages(userId);
synchronized (mLock) {
- if (!mUserUnlockedStates.contains(UserHandle.USER_SYSTEM)) {
+ if (!mUserUnlockedStates.contains(userId)) {
return false; // user is no longer unlocked
}
- final UserUsageStatsService userService = mUserState.get(UserHandle.USER_SYSTEM);
+ final UserUsageStatsService userService = mUserState.get(userId);
if (userService == null) {
return false; // user was stopped or removed
}
@@ -3055,44 +3053,35 @@
}
@Override
- public byte[] getBackupPayload(int user, String key) {
- if (!mUserUnlockedStates.contains(user)) {
- Slog.w(TAG, "Failed to get backup payload for locked user " + user);
+ public byte[] getBackupPayload(@UserIdInt int userId, String key) {
+ if (!mUserUnlockedStates.contains(userId)) {
+ Slog.w(TAG, "Failed to get backup payload for locked user " + userId);
return null;
}
synchronized (mLock) {
- // Check to ensure that only user 0's data is b/r for now
- // Note: if backup and restore is enabled for users other than the system user, the
- // #onUserUnlocked logic, specifically when the update mappings job is scheduled via
- // UsageStatsIdleService.scheduleUpdateMappingsJob, will have to be updated.
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
- if (userStats == null) {
- return null; // user was stopped or removed
- }
- return userStats.getBackupPayload(key);
- } else {
- return null;
+ final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(userId);
+ if (userStats == null) {
+ return null; // user was stopped or removed
}
+ Slog.i(TAG, "Returning backup payload for u=" + userId);
+ return userStats.getBackupPayload(key);
}
}
@Override
- public void applyRestoredPayload(int user, String key, byte[] payload) {
+ public void applyRestoredPayload(@UserIdInt int userId, String key, byte[] payload) {
synchronized (mLock) {
- if (!mUserUnlockedStates.contains(user)) {
- Slog.w(TAG, "Failed to apply restored payload for locked user " + user);
+ if (!mUserUnlockedStates.contains(userId)) {
+ Slog.w(TAG, "Failed to apply restored payload for locked user " + userId);
return;
}
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
- if (userStats == null) {
- return; // user was stopped or removed
- }
- final Set<String> restoredApps = userStats.applyRestoredPayload(key, payload);
- mAppStandby.restoreAppsToRare(restoredApps, user);
+ final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(userId);
+ if (userStats == null) {
+ return; // user was stopped or removed
}
+ final Set<String> restoredApps = userStats.applyRestoredPayload(key, payload);
+ mAppStandby.restoreAppsToRare(restoredApps, userId);
}
}
@@ -3165,8 +3154,8 @@
}
@Override
- public boolean updatePackageMappingsData() {
- return UsageStatsService.this.updatePackageMappingsData();
+ public boolean updatePackageMappingsData(@UserIdInt int userId) {
+ return UsageStatsService.this.updatePackageMappingsData(userId);
}
/**
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 28d726e..1a1af3b 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -866,7 +866,8 @@
public void simulateDisplayPortAltModeInfo(String portId, int partnerSinkStatus,
- int cableStatus, int numLanes, IndentingPrintWriter pw) {
+ int cableStatus, int numLanes, boolean hpd, int linkTrainingStatus,
+ IndentingPrintWriter pw) {
synchronized (mLock) {
final RawPortInfo portInfo = mSimulatedPorts.get(portId);
if (portInfo == null) {
@@ -875,7 +876,8 @@
}
DisplayPortAltModeInfo displayPortAltModeInfo =
- new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes);
+ new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes, hpd,
+ linkTrainingStatus);
portInfo.displayPortAltModeInfo = displayPortAltModeInfo;
pw.println("Simulating DisplayPort Info: " + displayPortAltModeInfo);
updatePortsLocked(pw, null);
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 7d84222..0aa1715 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -1169,14 +1169,17 @@
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
"", 0);
}
- } else if ("set-displayport-status".equals(args[0]) && args.length == 5) {
+ } else if ("set-displayport-status".equals(args[0]) && args.length == 7) {
final String portId = args[1];
final int partnerSinkStatus = Integer.parseInt(args[2]);
final int cableStatus = Integer.parseInt(args[3]);
final int displayPortNumLanes = Integer.parseInt(args[4]);
+ final boolean hpd = Boolean.parseBoolean(args[5]);
+ final int linkTrainingStatus = Integer.parseInt(args[6]);
if (mPortManager != null) {
mPortManager.simulateDisplayPortAltModeInfo(portId,
- partnerSinkStatus, cableStatus, displayPortNumLanes, pw);
+ partnerSinkStatus, cableStatus, displayPortNumLanes,
+ hpd, linkTrainingStatus, pw);
pw.println();
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
"", 0);
@@ -1187,7 +1190,10 @@
mPortManager.simulateDisplayPortAltModeInfo(portId,
DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
- 0, pw);
+ 0,
+ false,
+ 0,
+ pw);
pw.println();
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
"", 0);
@@ -1259,7 +1265,13 @@
pw.println("Example simulate DisplayPort Alt Mode Changes:");
pw.println(" dumpsys usb add-port \"matrix\" dual --displayport");
pw.println(" dumpsys usb set-displayport-status \"matrix\" <partner-sink>"
- + " <cable> <num-lanes>");
+ + " <cable> <num-lanes> <hpd> <link-training-status>");
+ pw.println("The required fields are as followed:");
+ pw.println(" <partner-sink>: type DisplayPortAltModeStatus");
+ pw.println(" <cable>: type DisplayPortAltModeStatus");
+ pw.println(" <num-lanes>: type int, expected 0, 2, or 4");
+ pw.println(" <hpd>: type boolean, expected true or false");
+ pw.println(" <link-training-status>: type int with range [0,2]");
pw.println(" dumpsys usb reset-displayport-status \"matrix\"");
pw.println("reset-displayport-status can also be used in order to set");
pw.println("the DisplayPortInfo to default values.");
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index b9ccace..c7a7a9b 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -639,7 +639,9 @@
altModeData.getDisplayPortAltModeData();
return new DisplayPortAltModeInfo(displayPortData.partnerSinkStatus,
displayPortData.cableStatus,
- toDisplayPortAltModeNumLanesInt(displayPortData.pinAssignment));
+ toDisplayPortAltModeNumLanesInt(displayPortData.pinAssignment),
+ displayPortData.hpd,
+ displayPortData.linkTrainingStatus);
}
}
return null;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS
index e5d0370..01b2cb9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS
@@ -1,2 +1,2 @@
-ytai@google.com
+atneya@google.com
elaurent@google.com
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/AudioSessionProviderImpl.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AudioSessionProviderImpl.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/AudioSessionProviderImpl.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AudioSessionProviderImpl.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/Dumpable.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/Dumpable.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/HalException.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/HalException.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/HalException.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/HalException.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/HalFactory.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/HalFactory.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/Hw2CompatUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/Hw2CompatUtil.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/Hw2CompatUtil.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/Hw2CompatUtil.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/OWNERS b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/OWNERS
new file mode 100644
index 0000000..01b2cb9
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/OWNERS
@@ -0,0 +1,2 @@
+atneya@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/README.md b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/README.md
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/README.md
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/README.md
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/RecoverableException.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/RecoverableException.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/RecoverableException.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/RecoverableException.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/TEST_MAPPING b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/TEST_MAPPING
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/TEST_MAPPING
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/TEST_MAPPING
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/UuidUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/UuidUtil.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/UuidUtil.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/UuidUtil.java
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
similarity index 100%
rename from services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index fd2907c..95a8e16 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -32,10 +32,8 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
/**
* A unified virtual device providing a means of voice (and other) communication on a device.
@@ -150,14 +148,6 @@
private final Object mLock = new Object();
- // Future used to delay terminating the InCallService before the call disconnect tone
- // finishes playing.
- private static Map<String, CompletableFuture<Void>> sDisconnectedToneFutures = new ArrayMap<>();
-
- // Timeout value to be used to ensure future completion for sDisconnectedToneFutures. This is
- // set to 4 seconds to account for the exceptional case (TONE_CONGESTION).
- private static final int DISCONNECTED_TONE_TIMEOUT = 4000;
-
Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
mInCallAdapter = adapter;
mCallingPackage = callingPackage;
@@ -466,45 +456,9 @@
}
private void fireCallRemoved(Call call) {
- String callId = call.internalGetCallId();
- CompletableFuture<Void> disconnectedToneFuture = initializeDisconnectedToneFuture(callId);
- // delay the InCallService termination until after the disconnect tone finishes playing
- disconnectedToneFuture.thenRunAsync(() -> {
- for (Listener listener : mListeners) {
- listener.onCallRemoved(this, call);
- }
- // clean up the future after
- sDisconnectedToneFutures.remove(callId);
- });
- }
-
- /**
- * Initialize disconnect tone future to be used in delaying ICS termination.
- *
- * @return CompletableFuture to delay InCallService termination until after the disconnect tone
- * finishes playing. A timeout of 4s is used to handle the use case when we play
- * TONE_CONGESTION and to ensure completion so that we don't block the removal of the service.
- */
- private CompletableFuture<Void> initializeDisconnectedToneFuture(String callId) {
- // create the future and map (sDisconnectedToneFutures) it to the corresponding call id
- CompletableFuture<Void> disconnectedToneFuture = new CompletableFuture<Void>()
- .completeOnTimeout(null, DISCONNECTED_TONE_TIMEOUT, TimeUnit.MILLISECONDS);
- // we should not encounter duplicate insertions since call ids are unique
- sDisconnectedToneFutures.put(callId, disconnectedToneFuture);
- return disconnectedToneFuture;
- }
-
- /**
- * Completes disconnected tone future with passed in result.
- * @hide
- * @return true if future was completed, false otherwise
- */
- public static boolean completeDisconnectedToneFuture(String callId) {
- if (sDisconnectedToneFutures.containsKey(callId)) {
- sDisconnectedToneFutures.get(callId).complete(null);
- return true;
+ for (Listener listener : mListeners) {
+ listener.onCallRemoved(this, call);
}
- return false;
}
private void fireCallAudioStateChanged(CallAudioState audioState) {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 26b4bbc..40488b1 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2547,8 +2547,6 @@
/**
* User is not associated with the subscription.
- * TODO(b/263279115): Make this error code public.
- * @hide
*/
public static final int RESULT_USER_NOT_ALLOWED = 33;
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a2d2019..cdb7d7c 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -1570,8 +1570,8 @@
/**
* Returns whether the passing portIndex is available.
- * A port is available if it is active without enabled profile on it or
- * calling app has carrier privilege over the profile installed on the selected port.
+ * A port is available if it is active without an enabled profile on it or calling app can
+ * activate a new profile on the selected port without any user interaction.
* Always returns false if the cardId is a physical card.
*
* @param portIndex is an enumeration of the ports available on the UICC.
diff --git a/telephony/java/android/telephony/ims/MediaQualityStatus.java b/telephony/java/android/telephony/ims/MediaQualityStatus.java
index 62c289a..5038aac 100644
--- a/telephony/java/android/telephony/ims/MediaQualityStatus.java
+++ b/telephony/java/android/telephony/ims/MediaQualityStatus.java
@@ -226,7 +226,7 @@
public Builder(
@NonNull String imsCallSessionId,
@MediaSessionType int mediaSessionType,
- int transportType) {
+ @TransportType int transportType) {
mImsCallSessionId = imsCallSessionId;
mMediaSessionType = mediaSessionType;
mTransportType = transportType;
diff --git a/tests/CanvasCompare/Android.bp b/tests/CanvasCompare/Android.bp
deleted file mode 100644
index 9883115..0000000
--- a/tests/CanvasCompare/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: [
- "frameworks_base_license",
- ],
-}
-
-android_test {
- name: "CanvasCompare",
- srcs: [
- "src/**/*.java",
- ":CanvasCompare-rscript{CanvasCompare.srcjar}",
- ],
- resource_zips: [
- ":CanvasCompare-rscript{CanvasCompare.res.zip}",
- ],
- platform_apis: true,
- libs: [
- "android.test.runner",
- "android.test.base",
- ],
- static_libs: ["junit"],
-}
-
-genrule {
- name: "CanvasCompare-rscript",
- srcs: [
- "src/**/*.rscript",
- ":rs_script_api",
- ":rs_clang_headers",
- ],
- tools: [
- "llvm-rs-cc",
- "soong_zip",
- ],
- out: [
- "CanvasCompare.srcjar",
- "CanvasCompare.res.zip",
- ],
- cmd: "for f in $(locations src/**/*.rscript); do " +
- " $(location llvm-rs-cc) -o $(genDir)/res/raw -p $(genDir)/src " +
- " -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " +
- " -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " +
- "done && " +
- "$(location soong_zip) -srcjar -o $(location CanvasCompare.srcjar) -C $(genDir)/src -D $(genDir)/src &&" +
- "$(location soong_zip) -o $(location CanvasCompare.res.zip) -C $(genDir)/res -D $(genDir)/res",
-}
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
deleted file mode 100644
index 2734e7f..0000000
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hwuicompare">
-
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
- <application android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo.Light.NoActionBar">
- <activity android:name="AutomaticActivity"
- android:label="CanvasAutoCompare"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <activity android:name="ManualActivity"
- android:label="CanvasManualCompare"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <uses-library android:name="android.test.runner"/>
- </application>
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.test.hwuicompare"
- android:label="HW/SW Canvas comparison tool."/>
-
-</manifest>
diff --git a/tests/CanvasCompare/OWNERS b/tests/CanvasCompare/OWNERS
deleted file mode 100644
index c88a9f8..0000000
--- a/tests/CanvasCompare/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /libs/hwui/OWNERS
diff --git a/tests/CanvasCompare/res/drawable/sunset1.jpg b/tests/CanvasCompare/res/drawable/sunset1.jpg
deleted file mode 100644
index 3b4e056..0000000
--- a/tests/CanvasCompare/res/drawable/sunset1.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/CanvasCompare/res/layout/automatic_layout.xml b/tests/CanvasCompare/res/layout/automatic_layout.xml
deleted file mode 100644
index e049ec0..0000000
--- a/tests/CanvasCompare/res/layout/automatic_layout.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.android.test.hwuicompare.MainView
- android:id="@+id/hardware_view"
- android:layout_width="@dimen/layer_width"
- android:layout_height="@dimen/layer_width" />
-
- <ImageView
- android:id="@+id/software_image_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true" />
-
- <ImageView
- android:id="@+id/hardware_image_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true" />
-
-</RelativeLayout>
diff --git a/tests/CanvasCompare/res/layout/manual_layout.xml b/tests/CanvasCompare/res/layout/manual_layout.xml
deleted file mode 100644
index 1a9288c..0000000
--- a/tests/CanvasCompare/res/layout/manual_layout.xml
+++ /dev/null
@@ -1,119 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
-
- <HorizontalScrollView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <LinearLayout
- android:id="@+id/spinner_layout"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" />
- </HorizontalScrollView>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:orientation="horizontal" >
-
- <com.android.test.hwuicompare.MainView
- android:id="@+id/hardware_view"
- android:layout_width="@dimen/layer_width"
- android:layout_height="@dimen/layer_width" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:orientation="horizontal" >
-
- <com.android.test.hwuicompare.MainView
- android:id="@+id/software_view"
- android:layout_width="@dimen/layer_width"
- android:layout_height="@dimen/layer_width" />
- </LinearLayout>
- </LinearLayout>
-
- <ImageView
- android:id="@+id/compare_image_view"
- android:layout_width="@dimen/layer_width_double"
- android:layout_height="@dimen/layer_height_double"
- android:filter="false" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal" >
-
- <ImageButton
- android:id="@+id/previous"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/previous_combination"
- android:src="@android:drawable/ic_media_previous" />
-
- <ImageButton
- android:id="@+id/next"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/next_combination"
- android:src="@android:drawable/ic_media_next" />
-
- <TextView
- android:id="@+id/current_error"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <Button
- android:id="@+id/show_hardware_version"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/show_hardware_version" />
-
- <Button
- android:id="@+id/show_software_version"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/show_software_version" />
-
- <Button
- android:id="@+id/show_error_heatmap"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/show_error_heatmap" />
- </LinearLayout>
-
-</LinearLayout>
diff --git a/tests/CanvasCompare/res/values/strings.xml b/tests/CanvasCompare/res/values/strings.xml
deleted file mode 100644
index edd4610..0000000
--- a/tests/CanvasCompare/res/values/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <string name="app_name">Canvas Compare Test</string>
-
- <!-- show hardware rendered version of the layer -->
- <string name="show_hardware_version">Hardware</string>
- <!-- show software rendered version of the layer -->
- <string name="show_software_version">Software</string>
- <!-- show layer error -->
- <string name="show_error_values">Error</string>
- <!-- show layer error heatmap -->
- <string name="show_error_heatmap">Heatmap</string>
- <!-- select and display the next combination of painting options-->
- <string name="next_combination">Next Combination</string>
- <!-- select and display the previous combination of painting options-->
- <string name="previous_combination">Previous Combination</string>
-</resources>
diff --git a/tests/CanvasCompare/res/values/values.xml b/tests/CanvasCompare/res/values/values.xml
deleted file mode 100644
index f69378d..0000000
--- a/tests/CanvasCompare/res/values/values.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
-
- <!-- NOTE: the below MUST be multiples of 64 -->
- <dimen name="layer_height">320px</dimen>
- <dimen name="layer_width">320px</dimen>
-
- <dimen name="layer_height_double">640px</dimen>
- <dimen name="layer_width_double">640px</dimen>
-
-</resources>
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
deleted file mode 100644
index 8ccd4e2..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.TreeSet;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Trace;
-import android.util.Log;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-public class AutomaticActivity extends CompareActivity {
- private static final String LOG_TAG = "AutomaticActivity";
- private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
- protected static final boolean DRAW_BITMAPS = false;
-
- /**
- * Threshold of error change required to consider a test regressed/improved
- */
- private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
-
- private static final float[] ERROR_CUTOFFS = {
- 0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
- };
-
- private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
- private float mTotalTests = 0;
- private float mTotalError = 0;
- private int mTestsRegressed = 0;
- private int mTestsImproved = 0;
-
- private ImageView mSoftwareImageView = null;
- private ImageView mHardwareImageView = null;
-
-
- public abstract static class FinalCallback {
- abstract void report(String name, float value);
- void complete() {};
- }
-
- private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
-
- Runnable mRunnable = new Runnable() {
- @Override
- public void run() {
- loadBitmaps();
- if (mSoftwareBitmap == null || mHardwareBitmap == null) {
- Log.e(LOG_TAG, "bitmap is null");
- return;
- }
-
- if (DRAW_BITMAPS) {
- mSoftwareImageView.setImageBitmap(mSoftwareBitmap);
- mHardwareImageView.setImageBitmap(mHardwareBitmap);
- }
-
- Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "calculateError");
- float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
- Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
-
- final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
- handleError(modifierNames, error);
-
- if (DisplayModifier.step()) {
- finishTest();
- } else {
- mHardwareView.invalidate();
- if (DRAW_BITMAPS) {
- mSoftwareImageView.invalidate();
- mHardwareImageView.invalidate();
- }
- }
- mHandler.removeCallbacks(mRunnable);
- }
- };
-
- @Override
- protected void onPause() {
- super.onPause();
- mHandler.removeCallbacks(mRunnable);
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.automatic_layout);
-
- mSoftwareImageView = findViewById(R.id.software_image_view);
- mHardwareImageView = findViewById(R.id.hardware_image_view);
-
- onCreateCommon(mRunnable);
- beginTest();
- }
-
- private static class TestResult {
- TestResult(String label, float error) {
- mLabel = label;
- mTotalError = error;
- mCount = 1;
- }
- public void addInto(float error) {
- mTotalError += error;
- mCount++;
- }
- public float getAverage() {
- return mTotalError / mCount;
- }
- final String mLabel;
- float mTotalError;
- int mCount;
- }
-
- JSONObject mOutputJson = null;
- JSONObject mInputJson = null;
- final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
- final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
- final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
- final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
- private void beginTest() {
- mFinalCallbacks.add(new FinalCallback() {
- @Override
- void report(String name, float value) {
- Log.d(LOG_TAG, name + " " + value);
- };
- });
-
- File inputFile = new File(Environment.getExternalStorageDirectory(),
- "CanvasCompareInput.json");
- if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
- try {
- FileInputStream inputStream = new FileInputStream(inputFile);
- Log.d(LOG_TAG, "Parsing input file...");
- StringBuffer content = new StringBuffer((int)inputFile.length());
- byte[] buffer = new byte[1024];
- while (inputStream.read(buffer) != -1) {
- content.append(new String(buffer));
- }
- mInputJson = new JSONObject(content.toString());
- inputStream.close();
- Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
- } catch (JSONException e) {
- Log.e(LOG_TAG, "error parsing input json", e);
- } catch (IOException e) {
- Log.e(LOG_TAG, "error reading input json from sd", e);
- }
- }
-
- mOutputJson = new JSONObject();
- }
-
- private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
- Log.d(LOG_TAG, "---------------");
- Log.d(LOG_TAG, label + ":");
- Log.d(LOG_TAG, "---------------");
- TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
- @Override
- public int compare(TestResult lhs, TestResult rhs) {
- if (lhs == rhs) return 0; // don't need to worry about complex equality
-
- int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
- if (cmp != 0) {
- return cmp;
- }
- return lhs.mLabel.compareTo(rhs.mLabel);
- }
- });
-
- for (TestResult t : map.values()) {
- set.add(t);
- }
-
- for (TestResult t : set.descendingSet()) {
- if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
- Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
- }
- }
- Log.d(LOG_TAG, "");
- }
-
- private void finishTest() {
- for (FinalCallback c : mFinalCallbacks) {
- c.report("averageError", (mTotalError / mTotalTests));
- for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
- c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
- mErrorRates[i]);
- }
- if (mInputJson != null) {
- c.report("tests regressed", mTestsRegressed);
- c.report("tests improved", mTestsImproved);
- }
- c.complete();
- }
-
- try {
- if (mOutputJson != null) {
- String outputString = mOutputJson.toString(4);
- File outputFile = new File(Environment.getExternalStorageDirectory(),
- "CanvasCompareOutput.json");
- FileOutputStream outputStream = new FileOutputStream(outputFile);
- outputStream.write(outputString.getBytes());
- outputStream.close();
- Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, "error during JSON stringify", e);
- } catch (IOException e) {
- Log.e(LOG_TAG, "error storing JSON output on sd", e);
- }
-
- logTestResultHash("Modifier change vs previous", mModifierDiffResults);
- logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
- logTestResultHash("Modifier average test results", mModifierResults);
- logTestResultHash("Individual test results", mIndividualResults);
-
- Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
- finish();
- }
-
- /**
- * Inserts the error value into all TestResult objects, associated with each of its modifiers
- */
- private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
- HashMap<String, TestResult> modifierResults) {
- for (String modifierName : modifierNames) {
- TestResult r = modifierResults.get(fullName);
- if (r == null) {
- modifierResults.put(modifierName, new TestResult(modifierName, error));
- } else {
- r.addInto(error);
- }
- }
- }
-
- private void handleError(final String[] modifierNames, final float error) {
- String fullName = "";
- for (String s : modifierNames) {
- fullName = fullName.concat("." + s);
- }
- fullName = fullName.substring(1);
-
- float deltaError = 0;
- if (mInputJson != null) {
- try {
- deltaError = error - (float)mInputJson.getDouble(fullName);
- } catch (JSONException e) {
- Log.w(LOG_TAG, "Warning: unable to read from input json", e);
- }
- if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
- if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
- mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
- addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
- }
-
- mIndividualResults.put(fullName, new TestResult(fullName, error));
- addForAllModifiers(fullName, error, modifierNames, mModifierResults);
-
- try {
- if (mOutputJson != null) {
- mOutputJson.put(fullName, error);
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, "exception during JSON recording", e);
- mOutputJson = null;
- }
-
- for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
- if (error <= ERROR_CUTOFFS[i]) break;
- mErrorRates[i]++;
- }
- mTotalError += error;
- mTotalTests++;
- }
-
- @Override
- protected boolean forceRecreateBitmaps() {
- // disable, unless needed for drawing into imageviews
- return DRAW_BITMAPS;
- }
-
- // FOR TESTING
- public void setFinalCallback(FinalCallback c) {
- mFinalCallbacks.add(c);
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
deleted file mode 100644
index 0dec1de..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import com.android.test.hwuicompare.R;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Handler;
-import android.os.Trace;
-import android.util.Log;
-import android.view.View;
-
-abstract public class CompareActivity extends Activity {
- private static final String LOG_TAG = "CompareActivity";
-
- protected MainView mHardwareView = null;
-
- protected Bitmap mSoftwareBitmap;
- protected Bitmap mHardwareBitmap;
-
- protected ErrorCalculator mErrorCalculator;
-
- protected Handler mHandler;
-
- Runnable mDrawCallback = null;
- protected boolean mRedrewFlag = true;
-
- protected void onCreateCommon(final Runnable postDrawCallback) {
- mDrawCallback = new Runnable() {
- @Override
- public void run() {
- mRedrewFlag = true;
- mHandler.post(postDrawCallback);
- };
- };
- getWindow().setBackgroundDrawable(new ColorDrawable(0xffefefef));
- ResourceModifiers.init(getResources());
-
- mHardwareView = findViewById(R.id.hardware_view);
- mHardwareView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mHardwareView.setBackgroundColor(Color.WHITE);
- mHardwareView.addDrawCallback(mDrawCallback);
-
- int width = getResources().getDimensionPixelSize(R.dimen.layer_width);
- int height = getResources().getDimensionPixelSize(R.dimen.layer_height);
- mSoftwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mHardwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-
- mErrorCalculator = new ErrorCalculator(getApplicationContext(), getResources());
-
- mHandler = new Handler();
- }
-
- protected abstract boolean forceRecreateBitmaps();
-
- protected void loadBitmaps() {
- Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "loadBitmaps");
- if (forceRecreateBitmaps()) {
- int width = mSoftwareBitmap.getWidth();
- int height = mSoftwareBitmap.getHeight();
-
- mSoftwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mHardwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- }
-
- Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "softwareDraw");
- mHardwareView.draw(new Canvas(mSoftwareBitmap));
- Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
-
- try {
- Method getHardwareLayer = View.class.getDeclaredMethod("getHardwareLayer");
- if (!getHardwareLayer.isAccessible())
- getHardwareLayer.setAccessible(true);
- Object hardwareLayer = getHardwareLayer.invoke(mHardwareView);
- if (hardwareLayer == null) {
- Log.d(LOG_TAG, "failure to access hardware layer");
- return;
- }
- Method copyInto = hardwareLayer.getClass()
- .getDeclaredMethod("copyInto", Bitmap.class);
- if (!copyInto.isAccessible())
- copyInto.setAccessible(true);
-
- Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "copyInto");
- boolean success = (Boolean) copyInto.invoke(hardwareLayer, mHardwareBitmap);
- Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
- if (!success) {
- Log.d(LOG_TAG, "failure to copy hardware layer into bitmap");
- }
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
deleted file mode 100644
index 4bcf5a4..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import static java.util.Map.entry;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.util.Log;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-public abstract class DisplayModifier {
-
- // automated tests ignore any combination of operations that don't together return TOTAL_MASK
- protected final static int TOTAL_MASK = 0x1F;
-
- // if we're filling, ensure we're not also sweeping over stroke parameters
- protected final static int SWEEP_STROKE_WIDTH_BIT = 0x1 << 0;
- protected final static int SWEEP_STROKE_CAP_BIT = 0x1 << 1;
- protected final static int SWEEP_STROKE_JOIN_BIT = 0x1 << 2;
-
- protected final static int SWEEP_SHADER_BIT = 0x1 << 3; // only allow non-simple shaders to use rectangle drawing
- protected final static int SWEEP_TRANSFORM_BIT = 0x1 << 4; // only sweep over specified transforms
-
- abstract public void modifyDrawing(Paint paint, Canvas canvas);
- protected int mask() { return 0x0; };
-
- private static final RectF gRect = new RectF(0, 0, 200, 175);
- private static final float[] gPts = new float[] {
- 0, 100, 100, 0, 100, 200, 200, 100
- };
-
- private static final int NUM_PARALLEL_LINES = 24;
- private static final float[] gTriPts = new float[] {
- 75, 0, 130, 130, 130, 130, 0, 130, 0, 130, 75, 0
- };
- private static final float[] gLinePts = new float[NUM_PARALLEL_LINES * 8 + gTriPts.length];
- static {
- int index;
- for (index = 0; index < gTriPts.length; index++) {
- gLinePts[index] = gTriPts[index];
- }
- float val = 0;
- for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
- gLinePts[index + 0] = 150;
- gLinePts[index + 1] = val;
- gLinePts[index + 2] = 300;
- gLinePts[index + 3] = val;
- index += 4;
- val += 8 + (2.0f/NUM_PARALLEL_LINES);
- }
- val = 0;
- for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
- gLinePts[index + 0] = val;
- gLinePts[index + 1] = 150;
- gLinePts[index + 2] = val;
- gLinePts[index + 3] = 300;
- index += 4;
- val += 8 + (2.0f/NUM_PARALLEL_LINES);
- }
- };
-
- @SuppressWarnings("serial")
- private static final Map<String, Map<String, DisplayModifier>> gMaps = Map.of(
- "aa", Map.of(
- "true", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setAntiAlias(true);
- }
- },
- "false", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setAntiAlias(false);
- }
- }),
- "style", Map.of(
- "fill", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStyle(Paint.Style.FILL);
- }
- },
- "stroke", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStyle(Paint.Style.STROKE);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
- },
- "fillAndStroke", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- }
-
- @Override
- protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
- }),
- "strokeWidth", Map.of(
- "hair", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeWidth(0);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
- },
- "0.3", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeWidth(0.3f);
- }
- },
- "1", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeWidth(1);
- }
- },
- "5", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeWidth(5);
- }
- },
- "30", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeWidth(30);
- }
- }),
- "strokeCap", Map.of(
- "butt", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeCap(Paint.Cap.BUTT);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_CAP_BIT; }
- },
- "round", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeCap(Paint.Cap.ROUND);
- }
- },
- "square", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeCap(Paint.Cap.SQUARE);
- }
- }),
- "strokeJoin", Map.of(
- "bevel", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeJoin(Paint.Join.BEVEL);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_JOIN_BIT; }
- },
- "round", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeJoin(Paint.Join.ROUND);
- }
- },
- "miter", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setStrokeJoin(Paint.Join.MITER);
- }
- }),
- // TODO: add miter0, miter1 etc to test miter distances
- "transform", Map.of(
- "noTransform", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {}
- @Override
- protected int mask() { return SWEEP_TRANSFORM_BIT; };
- },
- "rotate5", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.rotate(5);
- }
- },
- "rotate45", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.rotate(45);
- }
- },
- "rotate90", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.rotate(90);
- canvas.translate(0, -200);
- }
- },
- "scale2x2", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.scale(2, 2);
- }
- @Override
- protected int mask() { return SWEEP_TRANSFORM_BIT; };
- },
- "rot20scl1x4", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.rotate(20);
- canvas.scale(1, 4);
- }
- @Override
- protected int mask() { return SWEEP_TRANSFORM_BIT; };
- }),
- "shader", Map.ofEntries(
- entry("noShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {}
- @Override
- protected int mask() { return SWEEP_SHADER_BIT; };
- }),
- entry("repeatShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mRepeatShader);
- }
- @Override
- protected int mask() { return SWEEP_SHADER_BIT; };
- }),
- entry("translatedShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mTranslatedShader);
- }
- }),
- entry("scaledShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mScaledShader);
- }
- }),
- entry("horGradient", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mHorGradient);
- }
- }),
- entry("diagGradient", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mDiagGradient);
- }
- @Override
- protected int mask() { return SWEEP_SHADER_BIT; };
- }),
- entry("vertGradient", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mVertGradient);
- }
- }),
- entry("radGradient", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mRadGradient);
- }
- }),
- entry("sweepGradient", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mSweepGradient);
- }
- }),
- entry("composeShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mComposeShader);
- }
- }),
- entry("bad composeShader", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mBadComposeShader);
- }
- }),
- entry("bad composeShader 2", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader);
- }
- })),
- "drawing", Map.ofEntries(
- entry("roundRect", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawRoundRect(gRect, 20, 20, paint);
- }
- }),
- entry("rect", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawRect(gRect, paint);
- }
- @Override
- protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; };
- }),
- entry("circle", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawCircle(100, 100, 75, paint);
- }
- }),
- entry("oval", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawOval(gRect, paint);
- }
- }),
- entry("lines", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawLines(gLinePts, paint);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_CAP_BIT; };
- }),
- entry("plusPoints", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawPoints(gPts, paint);
- }
- }),
- entry("text", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setTextSize(36);
- canvas.drawText("TEXTTEST", 0, 50, paint);
- }
- }),
- entry("shadowtext", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- paint.setTextSize(36);
- paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff);
- canvas.drawText("TEXTTEST", 0, 50, paint);
- }
- }),
- entry("bitmapMesh", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3,
- ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null);
- }
- }),
- entry("arc", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawArc(gRect, 260, 285, false, paint);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_CAP_BIT; };
- }),
- entry("arcFromCenter", new DisplayModifier() {
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawArc(gRect, 260, 285, true, paint);
- }
- @Override
- protected int mask() { return SWEEP_STROKE_JOIN_BIT; };
- })));
- // WARNING: DON'T PUT MORE MAPS BELOW THIS
-
- private static Map<String, DisplayModifier> getMapAtIndex(int index) {
- for (Map<String, DisplayModifier> map : gMaps.values()) {
- if (index == 0) {
- return map;
- }
- index--;
- }
- return null;
- }
-
- // indices instead of iterators for easier bidirectional traversal
- private static final int mIndices[] = new int[gMaps.size()];
- private static final String[] mLastAppliedModifications = new String[gMaps.size()];
-
- private static boolean stepInternal(boolean forward) {
- int modifierMapIndex = gMaps.size() - 1;
- while (modifierMapIndex >= 0) {
- Map<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex);
- mIndices[modifierMapIndex] += (forward ? 1 : -1);
-
- if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) {
- break;
- }
-
- mIndices[modifierMapIndex] = (forward ? 0 : map.size() - 1);
- modifierMapIndex--;
- }
- return modifierMapIndex < 0; // true if resetting
- }
-
- public static boolean step() {
- boolean ret = false;
- do {
- ret |= stepInternal(true);
- } while (!checkModificationStateMask());
- return ret;
- }
-
- public static boolean stepBack() {
- boolean ret = false;
- do {
- ret |= stepInternal(false);
- } while (!checkModificationStateMask());
- return ret;
- }
-
- private static boolean checkModificationStateMask() {
- int operatorMask = 0x0;
- int mapIndex = 0;
- for (Map<String, DisplayModifier> map : gMaps.values()) {
- int displayModifierIndex = mIndices[mapIndex];
- for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) {
- if (displayModifierIndex == 0) {
- mLastAppliedModifications[mapIndex] = modifierEntry.getKey();
- operatorMask |= modifierEntry.getValue().mask();
- break;
- }
- displayModifierIndex--;
- }
- mapIndex++;
- }
- return operatorMask == TOTAL_MASK;
- }
-
- public static void apply(Paint paint, Canvas canvas) {
- int mapIndex = 0;
- for (Map<String, DisplayModifier> map : gMaps.values()) {
- int displayModifierIndex = mIndices[mapIndex];
- for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) {
- if (displayModifierIndex == 0) {
- mLastAppliedModifications[mapIndex] = modifierEntry.getKey();
- modifierEntry.getValue().modifyDrawing(paint, canvas);
- break;
- }
- displayModifierIndex--;
- }
- mapIndex++;
- }
- }
-
- public static String[] getLastAppliedModifications() {
- return mLastAppliedModifications.clone();
- }
-
- public static String[][] getStrings() {
- String[][] keys = new String[gMaps.size()][];
-
- int i = 0;
- for (Map<String, DisplayModifier> map : gMaps.values()) {
- keys[i] = new String[map.size()];
- int j = 0;
- for (String key : map.keySet()) {
- keys[i][j++] = key;
- }
- i++;
- }
-
- return keys;
- }
-
- public static void setIndex(int mapIndex, int newIndexValue) {
- mIndices[mapIndex] = newIndexValue;
- }
-
- public static int[] getIndices() {
- return mIndices;
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
deleted file mode 100644
index d402699..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.util.Log;
-
-public class ErrorCalculator {
- private static final String LOG_TAG = "ErrorCalculator";
- private static final int REGION_SIZE = 8;
-
- private static final boolean LOG_TIMING = false;
- private static final boolean LOG_CALC = false;
-
- private RenderScript mRS;
- private Allocation mIdealPixelsAllocation;
- private Allocation mGivenPixelsAllocation;
- private Allocation mOutputPixelsAllocation;
-
- private Allocation mInputRowsAllocation;
- private Allocation mOutputRegionsAllocation;
-
- private ScriptC_errorCalculator mScript;
-
- private int[] mOutputRowRegions;
-
- public ErrorCalculator(Context c, Resources resources) {
- int width = resources.getDimensionPixelSize(R.dimen.layer_width);
- int height = resources.getDimensionPixelSize(R.dimen.layer_height);
- mOutputRowRegions = new int[height / REGION_SIZE];
-
- mRS = RenderScript.create(c);
- int[] rowIndices = new int[height / REGION_SIZE];
- for (int i = 0; i < rowIndices.length; i++)
- rowIndices[i] = i * REGION_SIZE;
-
- mScript = new ScriptC_errorCalculator(mRS);
- mScript.set_HEIGHT(height);
- mScript.set_WIDTH(width);
- mScript.set_REGION_SIZE(REGION_SIZE);
-
- mInputRowsAllocation = Allocation.createSized(mRS, Element.I32(mRS), rowIndices.length,
- Allocation.USAGE_SCRIPT);
- mInputRowsAllocation.copyFrom(rowIndices);
- mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
- mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
- }
-
-
- private static long startMillis, middleMillis;
-
- public float calcErrorRS(Bitmap ideal, Bitmap given) {
- if (LOG_TIMING) {
- startMillis = System.currentTimeMillis();
- }
-
- mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-
- mScript.set_ideal(mIdealPixelsAllocation);
- mScript.set_given(mGivenPixelsAllocation);
-
- mScript.forEach_countInterestingRegions(mInputRowsAllocation, mOutputRegionsAllocation);
- mOutputRegionsAllocation.copyTo(mOutputRowRegions);
-
- int regionCount = 0;
- for (int region : mOutputRowRegions) {
- regionCount += region;
- }
- int interestingPixels = Math.max(1, regionCount) * REGION_SIZE * REGION_SIZE;
-
- if (LOG_TIMING) {
- long startMillis2 = System.currentTimeMillis();
- }
-
- mScript.forEach_accumulateError(mInputRowsAllocation, mOutputRegionsAllocation);
- mOutputRegionsAllocation.copyTo(mOutputRowRegions);
- float totalError = 0;
- for (int row : mOutputRowRegions) {
- totalError += row;
- }
- totalError /= 1024.0f;
-
- if (LOG_TIMING) {
- long finalMillis = System.currentTimeMillis();
- Log.d(LOG_TAG, "rs: first part took " + (middleMillis - startMillis) + "ms");
- Log.d(LOG_TAG, "rs: last part took " + (finalMillis - middleMillis) + "ms");
- }
- if (LOG_CALC) {
- Log.d(LOG_TAG, "rs: error " + totalError + ", pixels " + interestingPixels);
- }
- return totalError / interestingPixels;
- }
-
- public void calcErrorHeatmapRS(Bitmap ideal, Bitmap given, Bitmap output) {
- mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-
- mScript.set_ideal(mIdealPixelsAllocation);
- mScript.set_given(mGivenPixelsAllocation);
-
- mOutputPixelsAllocation = Allocation.createFromBitmap(mRS, output,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- mScript.forEach_displayDifference(mOutputPixelsAllocation, mOutputPixelsAllocation);
- mOutputPixelsAllocation.copyTo(output);
- }
-
- public static float calcError(Bitmap ideal, Bitmap given) {
- if (LOG_TIMING) {
- startMillis = System.currentTimeMillis();
- }
-
- int interestingRegions = 0;
- for (int x = 0; x < ideal.getWidth(); x += REGION_SIZE) {
- for (int y = 0; y < ideal.getWidth(); y += REGION_SIZE) {
- if (inspectRegion(ideal, x, y)) {
- interestingRegions++;
- }
- }
- }
-
- int interestingPixels = Math.max(1, interestingRegions) * REGION_SIZE * REGION_SIZE;
-
- if (LOG_TIMING) {
- long startMillis2 = System.currentTimeMillis();
- }
-
- float totalError = 0;
- for (int x = 0; x < ideal.getWidth(); x++) {
- for (int y = 0; y < ideal.getHeight(); y++) {
- int idealColor = ideal.getPixel(x, y);
- int givenColor = given.getPixel(x, y);
- if (idealColor == givenColor)
- continue;
- totalError += Math.abs(Color.red(idealColor) - Color.red(givenColor));
- totalError += Math.abs(Color.green(idealColor) - Color.green(givenColor));
- totalError += Math.abs(Color.blue(idealColor) - Color.blue(givenColor));
- totalError += Math.abs(Color.alpha(idealColor) - Color.alpha(givenColor));
- }
- }
- totalError /= 1024.0f;
- if (LOG_TIMING) {
- long finalMillis = System.currentTimeMillis();
- Log.d(LOG_TAG, "dvk: first part took " + (middleMillis - startMillis) + "ms");
- Log.d(LOG_TAG, "dvk: last part took " + (finalMillis - middleMillis) + "ms");
- }
- if (LOG_CALC) {
- Log.d(LOG_TAG, "dvk: error " + totalError + ", pixels " + interestingPixels);
- }
- return totalError / interestingPixels;
- }
-
- private static boolean inspectRegion(Bitmap ideal, int x, int y) {
- int regionColor = ideal.getPixel(x, y);
- for (int i = 0; i < REGION_SIZE; i++) {
- for (int j = 0; j < REGION_SIZE; j++) {
- if (ideal.getPixel(x + i, y + j) != regionColor)
- return true;
- }
- }
- return false;
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/MainView.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/MainView.java
deleted file mode 100644
index 454fe7b..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/MainView.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class MainView extends View {
- Paint mPaint = new Paint();
-
- public MainView(Context context) {
- super(context);
- }
-
- public MainView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public MainView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- mPaint.reset();
- DisplayModifier.apply(mPaint, canvas);
-
- if (mDrawCallback != null) {
- mDrawCallback.run();
- }
- }
-
- private Runnable mDrawCallback;
- public void addDrawCallback(Runnable drawCallback) {
- mDrawCallback = drawCallback;
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
deleted file mode 100644
index 405ff65..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import com.android.test.hwuicompare.R;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-public class ManualActivity extends CompareActivity {
- private static final String LOG_TAG = "ManualActivity";
- private ImageView mCompareImageView;
- private Bitmap mCompareBitmap;
- private TextView mErrorTextView;
- private MainView mSoftwareView;
-
- private static final int COMPARE_VIEW_UNINITIALIZED = -1;
- private static final int COMPARE_VIEW_HARDWARE = 0;
- private static final int COMPARE_VIEW_SOFTWARE = 1;
- private static final int COMPARE_VIEW_HEATMAP = 2; // TODO: add more like this? any ideas?
-
- private int mCompareImageViewState = COMPARE_VIEW_UNINITIALIZED;
- private int mLastCompareImageViewState = COMPARE_VIEW_UNINITIALIZED;
-
- Runnable mRunnable = new Runnable() {
- @Override
- public void run() {
- Log.d(LOG_TAG, "mRunnable running, mRedrewFlag = " + mRedrewFlag);
-
- if (mRedrewFlag) {
- loadBitmaps();
- // recalculate error
- float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
- String modname = "";
- for (String s : DisplayModifier.getLastAppliedModifications()) {
- modname = modname.concat(s + ".");
- }
-
- Log.d(LOG_TAG, "error for " + modname + " is " + error);
- mErrorTextView.setText(String.format("%.4f", error));
- }
-
- if (mCompareImageViewState != mLastCompareImageViewState || mRedrewFlag) {
- switch (mCompareImageViewState) {
- case COMPARE_VIEW_UNINITIALIZED:
- // set to hardware
- case COMPARE_VIEW_HARDWARE:
- mCompareImageView.setImageBitmap(mHardwareBitmap);
- break;
- case COMPARE_VIEW_SOFTWARE:
- mCompareImageView.setImageBitmap(mSoftwareBitmap);
- break;
- case COMPARE_VIEW_HEATMAP:
- mErrorCalculator.calcErrorHeatmapRS(mSoftwareBitmap, mHardwareBitmap,
- mCompareBitmap);
- mCompareImageView.setImageBitmap(mCompareBitmap);
- break;
- }
- mCompareImageView.getDrawable().setFilterBitmap(false);
- mCompareImageView.invalidate();
- }
-
- mLastCompareImageViewState = mCompareImageViewState;
- mRedrewFlag = false;
- mHandler.removeCallbacks(mRunnable);
- }
- };
-
- private void redrawViews() {
- mHardwareView.invalidate();
- mSoftwareView.invalidate();
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.manual_layout);
- onCreateCommon(mRunnable);
-
- mSoftwareView = (MainView) findViewById(R.id.software_view);
- mSoftwareView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- mSoftwareView.setBackgroundColor(Color.WHITE);
- mSoftwareView.addDrawCallback(mDrawCallback);
-
- mCompareImageView = (ImageView) findViewById(R.id.compare_image_view);
-
- int width = getResources().getDimensionPixelSize(R.dimen.layer_width);
- int height = getResources().getDimensionPixelSize(R.dimen.layer_height);
- mCompareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-
- mErrorTextView = (TextView) findViewById(R.id.current_error);
- ((ImageButton) findViewById(R.id.next)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- DisplayModifier.step();
- updateSpinners();
- redrawViews();
- }
- });
- ((ImageButton) findViewById(R.id.previous)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- DisplayModifier.stepBack();
- updateSpinners();
- redrawViews();
- }
- });
- ((Button) findViewById(R.id.show_hardware_version))
- .setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mCompareImageViewState = COMPARE_VIEW_HARDWARE;
- mHandler.post(mRunnable);
- }
- });
- ((Button) findViewById(R.id.show_software_version))
- .setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mCompareImageViewState = COMPARE_VIEW_SOFTWARE;
- mHandler.post(mRunnable);
- }
- });
- ((Button) findViewById(R.id.show_error_heatmap)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mCompareImageViewState = COMPARE_VIEW_HEATMAP;
- mHandler.post(mRunnable);
- }
- });
-
- buildSpinnerLayout();
- }
-
- private class DisplayModifierSpinner extends Spinner {
- private final int mIndex;
-
- public DisplayModifierSpinner(int index) {
- super(ManualActivity.this);
- mIndex = index;
- setOnItemSelectedListener(new OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parentView, View selectedItem,
- int position, long id) {
- DisplayModifier.setIndex(mIndex, position);
- redrawViews();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parentView) {
- }
- });
- }
- }
-
- private Spinner[] mSpinners;
-
- private void buildSpinnerLayout() {
- LinearLayout layout = (LinearLayout) findViewById(R.id.spinner_layout);
- String[][] mapsStrings = DisplayModifier.getStrings();
- mSpinners = new Spinner[mapsStrings.length];
- int index = 0;
- for (String[] spinnerValues : mapsStrings) {
- mSpinners[index] = new DisplayModifierSpinner(index);
- mSpinners[index].setAdapter(new ArrayAdapter<String>(this,
- android.R.layout.simple_spinner_dropdown_item, spinnerValues));
- layout.addView(mSpinners[index]);
- index++;
- }
- Log.d(LOG_TAG, "created " + index + " spinners");
- }
-
- private void updateSpinners() {
- int[] indices = DisplayModifier.getIndices();
- for (int i = 0; i < mSpinners.length; i++) {
- mSpinners[i].setSelection(indices[i]);
- }
- }
-
- @Override
- protected boolean forceRecreateBitmaps() {
- // continually recreate bitmaps to avoid modifying bitmaps currently being drawn
- return true;
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java
deleted file mode 100644
index d522481..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import com.android.test.hwuicompare.R;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
-import android.graphics.Color;
-import android.graphics.ComposeShader;
-import android.graphics.LinearGradient;
-import android.graphics.PorterDuff;
-import android.graphics.RadialGradient;
-import android.graphics.SweepGradient;
-import android.graphics.Matrix;
-import android.graphics.Shader;
-
-public class ResourceModifiers {
- public final BitmapShader mRepeatShader;
- public final BitmapShader mTranslatedShader;
- public final BitmapShader mScaledShader;
- private final int mTexWidth;
- private final int mTexHeight;
- private final float mDrawWidth;
- private final float mDrawHeight;
- public final LinearGradient mHorGradient;
- public final LinearGradient mDiagGradient;
- public final LinearGradient mVertGradient;
- public final RadialGradient mRadGradient;
- public final SweepGradient mSweepGradient;
- public final ComposeShader mComposeShader;
- public final ComposeShader mBadComposeShader;
- public final ComposeShader mAnotherBadComposeShader;
- public final Bitmap mBitmap;
- private final Matrix mMtx1;
- private final Matrix mMtx2;
- private final Matrix mMtx3;
-
- public final float[] mBitmapVertices;
- public final int[] mBitmapColors;
-
- private static ResourceModifiers sInstance = null;
- public static ResourceModifiers instance() { return sInstance; }
- public static void init(Resources resources) {
- sInstance = new ResourceModifiers(resources);
- }
-
- public ResourceModifiers(Resources resources) {
- mBitmap = BitmapFactory.decodeResource(resources, R.drawable.sunset1);
- mTexWidth = mBitmap.getWidth();
- mTexHeight = mBitmap.getHeight();
-
- mDrawWidth = resources.getDimensionPixelSize(R.dimen.layer_width);
- mDrawHeight = resources.getDimensionPixelSize(R.dimen.layer_height);
-
- mRepeatShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT,
- Shader.TileMode.REPEAT);
-
- mTranslatedShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT,
- Shader.TileMode.REPEAT);
- mMtx1 = new Matrix();
- mMtx1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
- mMtx1.postRotate(45, 0, 0);
- mTranslatedShader.setLocalMatrix(mMtx1);
-
- mScaledShader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR,
- Shader.TileMode.MIRROR);
- mMtx2 = new Matrix();
- mMtx2.setScale(0.5f, 0.5f);
- mScaledShader.setLocalMatrix(mMtx2);
-
- mHorGradient = new LinearGradient(0.0f, 0.0f, 1.0f, 0.0f,
- Color.RED, Color.GREEN, Shader.TileMode.CLAMP);
- mMtx3 = new Matrix();
- mMtx3.setScale(mDrawHeight, 1.0f);
- mMtx3.postRotate(-90.0f);
- mMtx3.postTranslate(0.0f, mDrawHeight);
- mHorGradient.setLocalMatrix(mMtx3);
-
- mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 2.0f, mDrawHeight / 2.0f,
- Color.BLUE, Color.RED, Shader.TileMode.CLAMP);
-
- mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
- Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
-
- mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f,
- Color.YELLOW, Color.MAGENTA);
-
- mComposeShader = new ComposeShader(mRepeatShader, mHorGradient,
- PorterDuff.Mode.MULTIPLY);
-
- final float width = mBitmap.getWidth() / 8.0f;
- final float height = mBitmap.getHeight() / 8.0f;
-
- mBitmapVertices = new float[] {
- 0.0f, 0.0f, width, 0.0f, width * 2, 0.0f, width * 3, 0.0f,
- 0.0f, height, width, height, width * 2, height, width * 4, height,
- 0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2,
- 0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4,
- };
-
- mBitmapColors = new int[] {
- 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000,
- 0xff0000ff, 0xffff0000, 0xff00ff00, 0xff00ff00,
- 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00,
- 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000,
- };
-
- // Use a repeating gradient with many colors to test the non simple case.
- mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f,
- mBitmapColors, null, Shader.TileMode.REPEAT);
-
- mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader,
- PorterDuff.Mode.MULTIPLY);
-
- mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient,
- PorterDuff.Mode.MULTIPLY);
- }
-
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
deleted file mode 100644
index 1ff153c..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.android.test.hwuicompare;
-
-import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
-
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
-
-public class Test extends ActivityInstrumentationTestCase2<AutomaticActivity> {
- AutomaticActivity mActivity;
- private Bundle mBundle;
-
- public Test() {
- super(AutomaticActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mBundle = new Bundle();
- mActivity = getActivity();
- mActivity.setFinalCallback(new FinalCallback() {
-
- @Override
- void report(String key, float value) {
- mBundle.putFloat(key, value);
- }
- @Override
- void complete() {
- synchronized(mBundle) {
- mBundle.notify();
- }
- }
- });
- }
-
- public void testCanvas() {
- synchronized(mBundle) {
- try {
- mBundle.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- getInstrumentation().sendStatus(0, mBundle);
- }
-}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rscript b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rscript
deleted file mode 100644
index 0a1742e..0000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rscript
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.android.test.hwuicompare)
-
-int REGION_SIZE;
-int WIDTH;
-int HEIGHT;
-
-rs_allocation ideal;
-rs_allocation given;
-
-void countInterestingRegions(const int32_t *v_in, int32_t *v_out) {
- int y = v_in[0];
- v_out[0] = 0;
-
- for (int x = 0; x < HEIGHT; x += REGION_SIZE) {
- bool interestingRegion = false;
- uchar4 regionColor = rsGetElementAt_uchar4(ideal, x, y);
- for (int i = 0; i < REGION_SIZE && !interestingRegion; i++) {
- for (int j = 0; j < REGION_SIZE && !interestingRegion; j++) {
- uchar4 testVal = rsGetElementAt_uchar4(ideal, x + j, y + i);
- interestingRegion |= (testVal.r != regionColor.r);
- interestingRegion |= (testVal.g != regionColor.g);
- interestingRegion |= (testVal.b != regionColor.b);
- interestingRegion |= (testVal.a != regionColor.a);
- }
- }
- if (interestingRegion) {
- v_out[0]++;
- }
- }
-}
-
-void accumulateError(const int32_t *v_in, int32_t *v_out) {
- int startY = v_in[0];
- int error = 0;
- for (int y = startY; y < startY + REGION_SIZE; y++) {
- for (int x = 0; x < HEIGHT; x++) {
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, x, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, x, y);
-
- error += abs(idealPixel.x - givenPixel.x);
- error += abs(idealPixel.y - givenPixel.y);
- error += abs(idealPixel.z - givenPixel.z);
- error += abs(idealPixel.w - givenPixel.w);
- }
- }
- v_out[0] = error;
-}
-
-void displayDifference(const uchar4 *v_in, uchar4 *v_out, uint32_t x, uint32_t y) {
- float4 idealPixel = rsGetElementAt_float4(ideal, x, y);
- float4 givenPixel = rsGetElementAt_float4(given, x, y);
-
- float4 diff = idealPixel - givenPixel;
- float totalDiff = diff.x + diff.y + diff.z + diff.w;
- if (totalDiff < 0) {
- v_out[0] = rsPackColorTo8888(0, 0, clamp(-totalDiff/2.f, 0.f, 1.f));
- } else {
- v_out[0] = rsPackColorTo8888(clamp(totalDiff/2.f, 0.f, 1.f), 0, 0);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 7cfe879..8154b16 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -24,10 +24,12 @@
import com.android.server.wm.flicker.FlickerTestFactory
import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.common.service.PlatformConsts
import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
@@ -65,6 +67,13 @@
open class OpenAppNonResizeableTest(flicker: FlickerTest) : OpenAppFromLockTransition(flicker) {
override val testApp = NonResizeableAppHelper(instrumentation)
+ @Before
+ open fun before() {
+ // b/266384300 - The test causes the keyguard occluded state to be incorrect, disable
+ // it while enabling shell transitions
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Checks that the [ComponentNameMatcher.NAV_BAR] layer starts invisible, becomes visible during
* unlocking animation and remains visible at the end
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
index 41316d8..8d2af38 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.RequiresDevice
import android.view.KeyEvent
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
@@ -140,6 +140,12 @@
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ @Postsubmit
+ @Test
+ override fun navBarWindowIsVisibleAtStartAndEnd() {
+ super.navBarWindowIsVisibleAtStartAndEnd()
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/VectorDrawableTest/Android.bp b/tests/VectorDrawableTest/Android.bp
index 099d874..9da7c5f 100644
--- a/tests/VectorDrawableTest/Android.bp
+++ b/tests/VectorDrawableTest/Android.bp
@@ -26,7 +26,5 @@
android_test {
name: "VectorDrawableTest",
srcs: ["**/*.java"],
- // certificate set as platform to allow testing of @hidden APIs
- certificate: "platform",
platform_apis: true,
}
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 163e438..5334dac 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -158,15 +158,6 @@
<category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity android:name="LottieDrawableTest"
- android:label="Lottie test bed"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="com.android.test.dynamic.TEST" />
- </intent-filter>
- </activity>
</application>
</manifest>
diff --git a/tests/VectorDrawableTest/res/raw/lottie.json b/tests/VectorDrawableTest/res/raw/lottie.json
deleted file mode 100644
index fea571c..0000000
--- a/tests/VectorDrawableTest/res/raw/lottie.json
+++ /dev/null
@@ -1,123 +0,0 @@
-{
- "v":"4.6.9",
- "fr":60,
- "ip":0,
- "op":200,
- "w":800,
- "h":600,
- "nm":"Loader 1 JSON",
- "ddd":0,
-
-
- "layers":[
- {
- "ddd":0,
- "ind":1,
- "ty":4,
- "nm":"Custom Path 1",
- "ao": 0,
- "ip": 0,
- "op": 300,
- "st": 0,
- "sr": 1,
- "bm": 0,
- "ks": {
- "o": { "a":0, "k":100 },
- "r": { "a":1, "k": [
- { "s": [ 0 ], "e": [ 360], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
- { "t": 200 }
- ] },
- "p": { "a":0, "k":[ 300, 300, 0 ] },
- "a": { "a":0, "k":[ 100, 100, 0 ] },
- "s": { "a":1, "k":[
- { "s": [ 100, 100 ], "e": [ 200, 200 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
- { "s": [ 200, 200 ], "e": [ 100, 100 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
- { "t": 200 }
- ] }
- },
-
- "shapes":[
- {
- "ty":"gr",
- "it":[
- {
- "ty" : "sh",
- "nm" : "Path 1",
- "ks" : {
- "a" : 1,
- "k" : [
- {
- "s": [ {
- "i": [ [ 0, 50 ], [ -50, 0 ], [ 0, -50 ], [ 50, 0 ] ],
- "o": [ [ 0, -50 ], [ 50, 0 ], [ 0, 50 ], [ -50, 0 ] ],
- "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
- "c": true
- } ],
- "e": [ {
- "i": [ [ 50, 50 ], [ -50, 0 ], [ -50, -50 ], [ 50, 50 ] ],
- "o": [ [ 50, -50 ], [ 50, 0 ], [ -50, 50 ], [ -50, 50 ] ],
- "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
- "c": true
- } ],
- "i": { "x":0.5, "y":0.5 },
- "o": { "x":0.5, "y":0.5 },
- "t": 0
- },
- {
- "s": [ {
- "i": [ [ 50, 50 ], [ -50, 0 ], [ -50, -50 ], [ 50, 50 ] ],
- "o": [ [ 50, -50 ], [ 50, 0 ], [ -50, 50 ], [ -50, 50 ] ],
- "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
- "c": true
- } ],
- "e": [ {
- "i": [ [ 0, 50 ], [ -50, 0 ], [ 0, -50 ], [ 50, 0 ] ],
- "o": [ [ 0, -50 ], [ 50, 0 ], [ 0, 50 ], [ -50, 0 ] ],
- "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
- "c": true
- } ],
- "i": { "x":0.5, "y":0.5 },
- "o": { "x":0.5, "y":0.5 },
- "t": 100
- },
- {
- "t": 200
- }
- ]
- }
- },
-
- {
- "ty": "st",
- "nm": "Stroke 1",
- "lc": 1,
- "lj": 1,
- "ml": 4,
- "w" : { "a": 1, "k": [
- { "s": [ 30 ], "e": [ 50 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
- { "s": [ 50 ], "e": [ 30 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
- { "t": 200 }
- ] },
- "o" : { "a": 0, "k": 100 },
- "c" : { "a": 1, "k": [
- { "s": [ 0, 1, 0 ], "e": [ 1, 0, 0 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
- { "s": [ 1, 0, 0 ], "e": [ 0, 1, 0 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
- { "t": 200 }
- ] }
- },
-
- {
- "ty":"tr",
- "p" : { "a":0, "k":[ 0, 0 ] },
- "a" : { "a":0, "k":[ 0, 0 ] },
- "s" : { "a":0, "k":[ 100, 100 ] },
- "r" : { "a":0, "k": 0 },
- "o" : { "a":0, "k":100 },
- "nm": "Transform"
- }
- ]
- }
- ]
- }
- ]
- }
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java
deleted file mode 100644
index 05eae7b..0000000
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.dynamic;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.LottieDrawable;
-import android.os.Bundle;
-import android.view.View;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Scanner;
-
-@SuppressWarnings({"UnusedDeclaration"})
-public class LottieDrawableTest extends Activity {
- private static final String TAG = "LottieDrawableTest";
- static final int BACKGROUND = 0xFFF44336;
-
- class LottieDrawableView extends View {
- private Rect mLottieBounds;
-
- private LottieDrawable mLottie;
-
- LottieDrawableView(Context context, InputStream is) {
- super(context);
- Scanner s = new Scanner(is).useDelimiter("\\A");
- String json = s.hasNext() ? s.next() : "";
- try {
- mLottie = LottieDrawable.makeLottieDrawable(json);
- } catch (IOException e) {
- throw new RuntimeException(TAG + ": error parsing test Lottie");
- }
- mLottie.start();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawColor(BACKGROUND);
-
- mLottie.setBounds(mLottieBounds);
- mLottie.draw(canvas);
- }
-
- public void setLottieSize(Rect bounds) {
- mLottieBounds = bounds;
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- InputStream is = getResources().openRawResource(R.raw.lottie);
-
- LottieDrawableView view = new LottieDrawableView(this, is);
- view.setLottieSize(new Rect(0, 0, 900, 900));
- setContentView(view);
- }
-}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 965b073..34f884b 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -19,9 +19,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
-import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
-import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
@@ -143,6 +140,8 @@
@NonNull private TelephonySubscriptionTrackerCallback mCallback;
@NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker;
+ @NonNull private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
+
public TelephonySubscriptionTrackerTest() {
mContext = mock(Context.class);
mTestLooper = new TestLooper();
@@ -173,7 +172,7 @@
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
doReturn(TEST_CARRIER_CONFIG)
.when(mCarrierConfigManager)
- .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any());
// subId 1, 2 are in same subGrp, only subId 1 is active
doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
@@ -189,9 +188,15 @@
doReturn(2).when(mTelephonyManager).getActiveModemCount();
mCallback = mock(TelephonySubscriptionTrackerCallback.class);
+ // Capture CarrierConfigChangeListener to emulate the carrier config change notification
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
mTelephonySubscriptionTracker =
new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
mTelephonySubscriptionTracker.register();
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+ listenerArgumentCaptor.capture());
+ mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any());
doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2))
@@ -239,14 +244,11 @@
return intent;
}
- private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
- Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
- intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
- intent.putExtra(
- EXTRA_SUBSCRIPTION_INDEX,
- hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID);
-
- return intent;
+ private void sendCarrierConfigChange(boolean hasValidSubscription) {
+ mCarrierConfigChangeListener.onCarrierConfigChanged(
+ TEST_SIM_SLOT_INDEX,
+ hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID,
+ TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
}
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
@@ -302,14 +304,15 @@
any(),
eq(mHandler));
final IntentFilter filter = getIntentFilter();
- assertEquals(2, filter.countActions());
- assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
+ assertEquals(1, filter.countActions());
assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED));
verify(mSubscriptionManager)
.addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
assertNotNull(getOnSubscriptionsChangedListener());
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), any());
+
verify(mTelephonyManager, times(2))
.registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any());
verify(mTelephonyManager)
@@ -442,7 +445,7 @@
@Test
public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
@@ -454,7 +457,7 @@
.when(mSubscriptionManager)
.getAllSubscriptionInfoList();
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
// Expect an empty snapshot
@@ -465,7 +468,7 @@
public void testReceiveBroadcast_SlotCleared() throws Exception {
setupReadySubIds();
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ sendCarrierConfigChange(false /* hasValidSubscription */);
mTestLooper.dispatchAll();
verifyNoActiveSubscriptions();
@@ -476,7 +479,7 @@
public void testReceiveBroadcast_ConfigNotReady() throws Exception {
doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any());
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
// No interactions expected; config was not loaded
@@ -485,21 +488,21 @@
@Test
public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception {
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
assertNotNull(
mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList();
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
}
@Test
public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception {
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
reset(mCallback);
@@ -510,12 +513,12 @@
new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR});
doReturn(updatedConfig)
.when(mCarrierConfigManager)
- .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any());
Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap = new HashMap<>();
subIdToCarrierConfigMap.put(
TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig));
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback)
@@ -530,13 +533,13 @@
@Test
public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ sendCarrierConfigChange(true /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
assertNotNull(
mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
- mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ sendCarrierConfigChange(false /* hasValidSubscription */);
mTestLooper.dispatchAll();
verify(mCallback)
.onNewSnapshot(
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index d1957fb..c66f4e5 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -16,6 +16,8 @@
#include "DumpManifest.h"
+#include <androidfw/ApkParsing.h>
+
#include <algorithm>
#include <array>
#include <memory>
@@ -2729,19 +2731,25 @@
}));
supports_screen_ = screen ? screen : &default_screens;
- // Gather the supported architectures_ of the app
- std::set<std::string> architectures_from_apk;
+ bool has_renderscript_bitcode = false;
auto it = apk_->GetFileCollection()->Iterator();
while (it->HasNext()) {
- auto file_path = it->Next()->GetSource().path;
- if (file_path.starts_with("lib/")) {
- file_path = file_path.substr(4);
- size_t pos = file_path.find('/');
- if (pos != std::string::npos) {
- file_path = file_path.substr(0, pos);
- }
+ if (it->Next()->GetSource().path.ends_with(".bc")) {
+ has_renderscript_bitcode = true;
+ break;
+ }
+ }
- architectures_from_apk.insert(file_path);
+ // Gather the supported architectures_ of the app
+ std::set<std::string> architectures_from_apk;
+ it = apk_->GetFileCollection()->Iterator();
+ while (it->HasNext()) {
+ auto file_path = it->Next()->GetSource().path.c_str();
+
+ const char* last_slash =
+ android::util::ValidLibraryPathLastSlash(file_path, has_renderscript_bitcode, false);
+ if (last_slash) {
+ architectures_from_apk.insert(std::string(file_path + APK_LIB_LEN, last_slash));
}
}
diff --git a/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java b/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
index 1d479fc..4a821bb 100644
--- a/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
+++ b/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
@@ -21,6 +21,7 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -35,6 +36,7 @@
public boolean enable6GhzRnr;
public ArrayList<ChannelSettings> channelSettings;
public ArrayList<HiddenNetwork> hiddenNetworks;
+ public byte[] vendorIes;
/** public constructor */
public SingleScanSettings() { }
@@ -53,13 +55,15 @@
return scanType == settings.scanType
&& enable6GhzRnr == settings.enable6GhzRnr
&& channelSettings.equals(settings.channelSettings)
- && hiddenNetworks.equals(settings.hiddenNetworks);
+ && hiddenNetworks.equals(settings.hiddenNetworks)
+ && Arrays.equals(vendorIes, settings.vendorIes);
}
/** override hash code */
@Override
public int hashCode() {
- return Objects.hash(scanType, channelSettings, hiddenNetworks, enable6GhzRnr);
+ return Objects.hash(scanType, channelSettings, hiddenNetworks, enable6GhzRnr,
+ Arrays.hashCode(vendorIes));
}
@@ -88,6 +92,11 @@
out.writeBoolean(enable6GhzRnr);
out.writeTypedList(channelSettings);
out.writeTypedList(hiddenNetworks);
+ if (vendorIes == null) {
+ out.writeByteArray(new byte[0]);
+ } else {
+ out.writeByteArray(vendorIes);
+ }
}
/** implement Parcelable interface */
@@ -108,6 +117,10 @@
in.readTypedList(result.channelSettings, ChannelSettings.CREATOR);
result.hiddenNetworks = new ArrayList<HiddenNetwork>();
in.readTypedList(result.hiddenNetworks, HiddenNetwork.CREATOR);
+ result.vendorIes = in.createByteArray();
+ if (result.vendorIes == null) {
+ result.vendorIes = new byte[0];
+ }
if (in.dataAvail() != 0) {
Log.e(TAG, "Found trailing data after parcel parsing.");
}
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index 2ad5771..2a199d2 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -96,6 +96,10 @@
public static final String SCANNING_PARAM_ENABLE_6GHZ_RNR =
"android.net.wifi.nl80211.SCANNING_PARAM_ENABLE_6GHZ_RNR";
+ // Extra scanning parameter used to add vendor IEs (byte[]).
+ public static final String EXTRA_SCANNING_PARAM_VENDOR_IES =
+ "android.net.wifi.nl80211.extra.SCANNING_PARAM_VENDOR_IES";
+
private AlarmManager mAlarmManager;
private Handler mEventHandler;
@@ -1135,6 +1139,7 @@
settings.hiddenNetworks = new ArrayList<>();
if (extraScanningParams != null) {
settings.enable6GhzRnr = extraScanningParams.getBoolean(SCANNING_PARAM_ENABLE_6GHZ_RNR);
+ settings.vendorIes = extraScanningParams.getByteArray(EXTRA_SCANNING_PARAM_VENDOR_IES);
}
if (freqs != null) {
@@ -1169,7 +1174,7 @@
case IWifiScannerImpl.SCAN_STATUS_FAILED_ABORT:
return WifiScanner.REASON_ABORT;
case IWifiScannerImpl.SCAN_STATUS_FAILED_NODEV:
- return WifiScanner.REASON_NO_DEV;
+ return WifiScanner.REASON_NO_DEVICE;
case IWifiScannerImpl.SCAN_STATUS_FAILED_INVALID_ARGS:
return WifiScanner.REASON_INVALID_ARGS;
case IWifiScannerImpl.SCAN_STATUS_FAILED_GENERIC:
diff --git a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
index fd595fa..2fa17a1 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
@@ -47,6 +47,7 @@
private ChannelSettings mChannelSettings2;
private HiddenNetwork mHiddenNetwork1;
private HiddenNetwork mHiddenNetwork2;
+ private byte[] mVendorIes;
@Before
public void setUp() {
@@ -59,6 +60,9 @@
mHiddenNetwork1.ssid = TEST_SSID_1;
mHiddenNetwork2 = new HiddenNetwork();
mHiddenNetwork2.ssid = TEST_SSID_2;
+
+ mVendorIes = new byte[]{(byte) 0xdd, 0x7, 0x00, 0x50, (byte) 0xf2, 0x08, 0x11, 0x22, 0x33,
+ (byte) 0xdd, 0x7, 0x00, 0x50, (byte) 0xf2, 0x08, 0x44, 0x55, 0x66};
}
/**
@@ -69,12 +73,12 @@
public void canSerializeAndDeserialize() {
SingleScanSettings scanSettings = new SingleScanSettings();
scanSettings.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
-
scanSettings.channelSettings =
new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
scanSettings.hiddenNetworks =
new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
scanSettings.enable6GhzRnr = true;
+ scanSettings.vendorIes = mVendorIes;
Parcel parcel = Parcel.obtain();
scanSettings.writeToParcel(parcel, 0);
@@ -98,6 +102,7 @@
new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
scanSettings1.hiddenNetworks =
new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+ scanSettings1.vendorIes = mVendorIes;
SingleScanSettings scanSettings2 = new SingleScanSettings();
scanSettings2.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
@@ -105,6 +110,7 @@
new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
scanSettings2.hiddenNetworks =
new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+ scanSettings2.vendorIes = mVendorIes;
assertEquals(scanSettings1, scanSettings2);
assertEquals(scanSettings1.hashCode(), scanSettings2.hashCode());
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
index 5012622..362eb14 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
@@ -68,6 +68,7 @@
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -127,6 +128,9 @@
private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
private static final int[] TEST_FREQUENCIES_1 = {};
private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final byte[] TEST_VENDOR_IES =
+ new byte[]{(byte) 0xdd, 0x7, 0x00, 0x50, (byte) 0xf2, 0x08, 0x11, 0x22, 0x33,
+ (byte) 0xdd, 0x7, 0x00, 0x50, (byte) 0xf2, 0x08, 0x44, 0x55, 0x66};
private static final MacAddress TEST_RAW_MAC_BYTES = MacAddress.fromBytes(
new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05});
@@ -512,7 +516,7 @@
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false, null)));
}
/**
@@ -523,12 +527,13 @@
when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
Bundle bundle = new Bundle();
bundle.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR, true);
+ bundle.putByteArray(WifiNl80211Manager.EXTRA_SCANNING_PARAM_VENDOR_IES, TEST_VENDOR_IES);
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, bundle));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, true)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, true, TEST_VENDOR_IES)));
}
/**
@@ -542,7 +547,7 @@
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, null));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false, null)));
}
/**
@@ -556,7 +561,7 @@
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, new Bundle()));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false, null)));
}
/**
@@ -577,7 +582,7 @@
// But the argument passed down should have the duplicate removed.
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false, null)));
}
/**
@@ -589,7 +594,7 @@
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
- IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null, false)));
+ IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null, false, null)));
}
/**
@@ -1161,13 +1166,15 @@
private final Set<Integer> mExpectedFreqs;
private final List<byte[]> mExpectedSsids;
private final boolean mExpectedEnable6GhzRnr;
+ private final byte[] mExpectedVendorIes;
ScanMatcher(int expectedScanType, Set<Integer> expectedFreqs, List<byte[]> expectedSsids,
- boolean expectedEnable6GhzRnr) {
+ boolean expectedEnable6GhzRnr, byte[] expectedVendorIes) {
this.mExpectedScanType = expectedScanType;
this.mExpectedFreqs = expectedFreqs;
this.mExpectedSsids = expectedSsids;
this.mExpectedEnable6GhzRnr = expectedEnable6GhzRnr;
+ this.mExpectedVendorIes = expectedVendorIes;
}
@Override
@@ -1202,12 +1209,15 @@
if (!mExpectedSsids.equals(ssidSet)) {
return false;
}
-
} else {
if (hiddenNetworks != null && hiddenNetworks.size() > 0) {
return false;
}
}
+
+ if (!Arrays.equals(mExpectedVendorIes, settings.vendorIes)) {
+ return false;
+ }
return true;
}