Merge "Import translations. DO NOT MERGE ANYWHERE"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 1cd5d96..a976de3 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -19,6 +19,8 @@
import android.graphics.Canvas;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
+import android.graphics.text.LineBreakConfig;
+import android.os.LocaleList;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -43,6 +45,19 @@
public StaticLayoutPerfTest() {}
+ public static final String JP_TEXT_SHORT = "日本語でのパフォーマンス計測のための例文です。";
+ // About 350 chars
+ public static final String JP_TEXT_LONG = "日本語でのパフォーマンス計測のための文章ですが、長いです。"
+ + "長い文章が必要なのですが、特に書くことが思いつかないので、コロッケの作り方でも書こうと思います。"
+ + "じゃがいもを茹でて潰しておきます。私は少し形が残っているほうが好きなので、ある程度のところで潰すのを"
+ + "やめます。別のフライパンで軽く塩をして玉ねぎのみじん切りを炒め、透き通ったら、一度取り出します。"
+ + "きれいにしたフライパンに、豚ひき肉を入れてあまりイジらずに豚肉を炒めます。"
+ + "しっかり火が通ったら炒めた玉ねぎを戻し入れ、塩コショウで味を決めます。"
+ + "炒めた肉玉ねぎとじゃがいもをよく混ぜて、1個あたり100gになるように整形します。"
+ + "整形したタネに小麦粉、卵、パン粉をつけて揚げます。"
+ + "180℃で揚げ、衣がきつね色になったら引き上げて、油を切る。"
+ + "盛り付けて出来上がり。";
+
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -432,4 +447,117 @@
}
}
+ @Test
+ public void testCreate_JPText_Phrase_Short() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_SHORT;
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_JPText_Phrase_Long() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_LONG;
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_JPText_Phrase_LongLong() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_LONG.repeat(20); // 250 * 20 = 7000 chars
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_JPText_NoPhrase_Short() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_SHORT;
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_JPText_NoPhrase_Long() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_LONG;
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_JPText_NoPhrase_LongLong() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final String text = JP_TEXT_LONG.repeat(20); // 250 * 20 = 7000 chars
+ final LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .build();
+ final TextPaint paint = new TextPaint(PAINT);
+ paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+ StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+ .setLineBreakConfig(config)
+ .build();
+ }
+ }
}
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
index 5befa1f..424d784 100644
--- a/apct-tests/perftests/multiuser/AndroidManifest.xml
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -15,8 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.perftests.multiuser">
-
+ package="com.android.perftests.multiuser">
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
@@ -27,6 +26,7 @@
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER" />
<application>
<uses-library android:name="android.test.runner" />
@@ -38,5 +38,4 @@
<queries>
<package android:name="perftests.multiuser.apps.dummyapp" />
</queries>
-
</manifest>
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index b24076a..64ba6d1 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -15,7 +15,11 @@
*/
package android.multiuser;
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
@@ -25,6 +29,7 @@
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.WaitResult;
+import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
@@ -34,6 +39,7 @@
import android.content.pm.IPackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IProgressListener;
@@ -59,6 +65,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -114,6 +121,7 @@
private ActivityManager mAm;
private IActivityManager mIam;
private PackageManager mPm;
+ private WallpaperManager mWm;
private ArrayList<Integer> mUsersToRemove;
private boolean mHasManagedUserFeature;
private BroadcastWaiter mBroadcastWaiter;
@@ -132,6 +140,7 @@
mIam = ActivityManager.getService();
mUsersToRemove = new ArrayList<>();
mPm = context.getPackageManager();
+ mWm = WallpaperManager.getInstance(context);
mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
mBroadcastWaiter = new BroadcastWaiter(context, TAG, TIMEOUT_IN_SECOND,
Intent.ACTION_USER_STARTED,
@@ -241,24 +250,27 @@
/**
* Tests starting an uninitialized user, with wait times in between iterations.
- * Measures the time until ACTION_USER_STARTED is received.
+ * Measures the time until the ProgressListener callback.
*/
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void startUser_realistic() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
final int userId = createUserNoFlags();
+ final ProgressWaiter waiter = new ProgressWaiter();
waitForBroadcastIdle();
- runThenWaitForBroadcasts(userId, () -> {
- mRunner.resumeTiming();
- Log.i(TAG, "Starting timer");
+ mRunner.resumeTiming();
+ Log.i(TAG, "Starting timer");
- mIam.startUserInBackground(userId);
- }, Intent.ACTION_USER_STARTED);
+ final boolean success = mIam.startUserInBackgroundWithListener(userId, waiter)
+ && waiter.waitForFinish(TIMEOUT_IN_SECOND * 1000);
mRunner.pauseTiming();
Log.i(TAG, "Stopping timer");
+
+ assertTrue("Error: could not start user " + userId, success);
+
removeUser(userId);
waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
@@ -372,6 +384,32 @@
removeUser(testUser);
}
+ /** Tests switching to a previously-started, but no-longer-running, user with wait
+ * times between iterations and using a static wallpaper */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void switchUser_stopped_staticWallpaper() throws RemoteException {
+ assumeTrue(mWm.isWallpaperSupported() && mWm.isSetWallpaperAllowed());
+ final int startUser = ActivityManager.getCurrentUser();
+ final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true,
+ /* useStaticWallpaper */true);
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ waitCoolDownPeriod();
+ Log.d(TAG, "Starting timer");
+ mRunner.resumeTiming();
+
+ switchUser(testUser);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ switchUserNoCheck(startUser);
+ stopUserAfterWaitingForBroadcastIdle(testUser, true);
+ attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
+ mRunner.resumeTimingForNextIteration();
+ }
+ removeUser(testUser);
+ }
+
/** Tests switching to an already-created already-running non-owner background user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser_running() throws RemoteException {
@@ -415,6 +453,31 @@
removeUser(testUser);
}
+ /** Tests switching to an already-created already-running non-owner background user, with wait
+ * times between iterations and using a default static wallpaper */
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
+ public void switchUser_running_staticWallpaper() throws RemoteException {
+ assumeTrue(mWm.isWallpaperSupported() && mWm.isSetWallpaperAllowed());
+ final int startUser = ActivityManager.getCurrentUser();
+ final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false,
+ /* useStaticWallpaper */ true);
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ waitCoolDownPeriod();
+ Log.d(TAG, "Starting timer");
+ mRunner.resumeTiming();
+
+ switchUser(testUser);
+
+ mRunner.pauseTiming();
+ Log.d(TAG, "Stopping timer");
+ waitForBroadcastIdle();
+ switchUserNoCheck(startUser);
+ mRunner.resumeTimingForNextIteration();
+ }
+ removeUser(testUser);
+ }
+
/** Tests stopping a background user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void stopUser() throws RemoteException {
@@ -843,14 +906,20 @@
waitForLatch("Failed to properly stop user " + userId, latch);
}
+ private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws RemoteException {
+ return initializeNewUserAndSwitchBack(stopNewUser, /* useStaticWallpaper */ false);
+ }
+
/**
* Creates a user and waits for its ACTION_USER_UNLOCKED.
* Then switches to back to the original user and waits for its switchUser() to finish.
*
* @param stopNewUser whether to stop the new user after switching to otherUser.
+ * @param useStaticWallpaper whether to switch the wallpaper of the default user to a static.
* @return userId of the newly created user.
*/
- private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws RemoteException {
+ private int initializeNewUserAndSwitchBack(boolean stopNewUser, boolean useStaticWallpaper)
+ throws RemoteException {
final int origUser = mAm.getCurrentUser();
// First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
final int testUser = createUserNoFlags();
@@ -858,6 +927,17 @@
mAm.switchUser(testUser);
}, Intent.ACTION_USER_UNLOCKED, Intent.ACTION_MEDIA_MOUNTED);
+ if (useStaticWallpaper) {
+ assertTrue(mWm.isWallpaperSupported() && mWm.isSetWallpaperAllowed());
+ try {
+ Bitmap blank = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ mWm.setBitmap(blank, /* visibleCropHint */ null, /* allowBackup */ true,
+ /* which */ FLAG_SYSTEM | FLAG_LOCK, testUser);
+ } catch (IOException exception) {
+ fail("Unable to set static wallpaper.");
+ }
+ }
+
// Second, switch back to origUser, waiting merely for switchUser() to finish
switchUser(origUser);
attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 439f54c..7ed4d35 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -800,22 +800,12 @@
* if {@code null} is passed as the {@code targetHandler} parameter.
*
* <p class="note"><strong>Note:</strong>
- * Starting with {@link Build.VERSION_CODES#S}, apps targeting SDK level 31 or higher
- * need to request the
- * {@link Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM} permission to use this
- * API, unless the app is exempt from battery restrictions.
- * The user and the system can revoke this permission via the special app access screen in
- * Settings.
+ * On previous android versions {@link Build.VERSION_CODES#S} and
+ * {@link Build.VERSION_CODES#TIRAMISU}, apps targeting SDK level 31 or higher needed to hold
+ * the {@link Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM} permission to use
+ * this API, unless the app was exempt from battery restrictions.
*
- * <p class="note"><strong>Note:</strong>
- * Exact alarms should only be used for user-facing features.
- * For more details, see <a
- * href="{@docRoot}about/versions/12/behavior-changes-12#exact-alarm-permission">
- * Exact alarm permission</a>.
- *
- * @see Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM
*/
- @RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
@NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, null, listener, tag,
@@ -949,7 +939,8 @@
* {@link #setExact(int, long, String, OnAlarmListener, Handler)} instead.
*
* <p>
- * Note that using this API requires you to hold
+ * Note that on previous Android versions {@link Build.VERSION_CODES#S} and
+ * {@link Build.VERSION_CODES#TIRAMISU}, using this API required you to hold
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM}, unless you are on the system's power
* allowlist. This can be set, for example, by marking the app as {@code <allow-in-power-save>}
* within the system config.
@@ -970,9 +961,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {
- Manifest.permission.UPDATE_DEVICE_STATS,
- Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional = true)
+ @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
@NonNull Executor executor, @NonNull WorkSource workSource,
@NonNull OnAlarmListener listener) {
@@ -1283,9 +1272,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {
- Manifest.permission.UPDATE_DEVICE_STATS,
- Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional = true)
+ @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
public void setExactAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
@Nullable String tag, @NonNull Executor executor, @Nullable WorkSource workSource,
@NonNull OnAlarmListener listener) {
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index 31d2266..1a205d0 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -73,16 +73,12 @@
* Detach the notification supplied to
* {@link #setNotification(JobParameters, int, Notification, int)} when the job ends.
* The notification will remain shown even after JobScheduler stops the job.
- *
- * @hide
*/
public static final int JOB_END_NOTIFICATION_POLICY_DETACH = 0;
/**
* Cancel and remove the notification supplied to
* {@link #setNotification(JobParameters, int, Notification, int)} when the job ends.
* The notification will be removed from the notification shade.
- *
- * @hide
*/
public static final int JOB_END_NOTIFICATION_POLICY_REMOVE = 1;
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index fd2bb13..69fe85e 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -92,6 +92,14 @@
* Caller had USE_EXACT_ALARM permission.
*/
static final int EXACT_ALLOW_REASON_POLICY_PERMISSION = 3;
+ /**
+ * Caller used a listener alarm, which does not need permission to be exact.
+ */
+ static final int EXACT_ALLOW_REASON_LISTENER = 4;
+ /**
+ * Caller used a prioritized alarm, which does not need permission to be exact.
+ */
+ static final int EXACT_ALLOW_REASON_PRIORITIZED = 5;
public final int type;
/**
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 d6d51e0..e41eb00 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -47,9 +47,11 @@
import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_LISTENER;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PRIORITIZED;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
@@ -2890,12 +2892,23 @@
// The API doesn't allow using both together.
flags &= ~FLAG_ALLOW_WHILE_IDLE;
// Prioritized alarms don't need any extra permission to be exact.
+ if (exact) {
+ exactAllowReason = EXACT_ALLOW_REASON_PRIORITIZED;
+ }
} else if (exact || allowWhileIdle) {
final boolean needsPermission;
boolean lowerQuota;
if (isExactAlarmChangeEnabled(callingPackage, callingUserId)) {
- needsPermission = exact;
- lowerQuota = !exact;
+ if (directReceiver == null) {
+ needsPermission = exact;
+ lowerQuota = !exact;
+ } else {
+ needsPermission = false;
+ lowerQuota = allowWhileIdle;
+ if (exact) {
+ exactAllowReason = EXACT_ALLOW_REASON_LISTENER;
+ }
+ }
if (exact) {
idleOptions = (alarmClock != null) ? mOptsWithFgsForAlarmClock.toBundle()
: mOptsWithFgs.toBundle();
@@ -2931,11 +2944,9 @@
throw new SecurityException(errorMessage);
}
// If the app is on the full system power allow-list (not except-idle),
- // or the user-elected allow-list, or we're in a soft failure mode, we still
- // allow the alarms.
- // In both cases, ALLOW_WHILE_IDLE alarms get a lower quota equivalent to
- // what pre-S apps got. Note that user-allow-listed apps don't use the flag
- // ALLOW_WHILE_IDLE.
+ // or the user-elected allow-list, we allow exact alarms.
+ // ALLOW_WHILE_IDLE alarms get a lower quota equivalent to what pre-S apps
+ // got. Note that user-allow-listed apps don't use FLAG_ALLOW_WHILE_IDLE.
// We grant temporary allow-list to allow-while-idle alarms but without FGS
// capability. AlarmClock alarms do not get the temporary allow-list.
// This is consistent with pre-S behavior. Note that apps that are in
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index 75ed616..28acb45 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -18,9 +18,11 @@
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
import android.app.ActivityManager;
@@ -84,14 +86,18 @@
private static int reasonToStatsReason(int reasonCode) {
switch (reasonCode) {
- case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
- return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
case Alarm.EXACT_ALLOW_REASON_PERMISSION:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
+ case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
case Alarm.EXACT_ALLOW_REASON_COMPAT:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
case Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
+ case Alarm.EXACT_ALLOW_REASON_LISTENER:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
+ case Alarm.EXACT_ALLOW_REASON_PRIORITIZED:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
default:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ed717c4..6998081 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -195,10 +195,35 @@
return;
}
+ if ("scheduling".equals(op)) {
+ setSchedulingEnabled(userId);
+ return;
+ }
+
System.err.println("Unknown command");
showUsage();
}
+ private void setSchedulingEnabled(int userId) {
+ String arg = nextArg();
+ if (arg == null) {
+ showUsage();
+ return;
+ }
+
+ try {
+ boolean enable = Boolean.parseBoolean(arg);
+ mBmgr.setFrameworkSchedulingEnabledForUser(userId, enable);
+ System.out.println(
+ "Backup scheduling is now "
+ + (enable ? "enabled" : "disabled")
+ + " for user "
+ + userId);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
private void handleRemoteException(RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -944,6 +969,7 @@
System.err.println(" bmgr activate BOOL");
System.err.println(" bmgr activated");
System.err.println(" bmgr autorestore BOOL");
+ System.err.println(" bmgr scheduling BOOL");
System.err.println("");
System.err.println("The '--user' option specifies the user on which the operation is run.");
System.err.println("It must be the first argument before the operation.");
@@ -1021,6 +1047,9 @@
System.err.println("");
System.err.println("The 'autorestore' command enables or disables automatic restore when");
System.err.println("a new package is installed.");
+ System.err.println("");
+ System.err.println("The 'scheduling' command enables or disables backup scheduling in the");
+ System.err.println("framework.");
}
private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/core/api/current.txt b/core/api/current.txt
index bec2559..801da28 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4635,8 +4635,9 @@
method @Nullable public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
method public boolean getLockTaskMode();
+ method public int getPendingIntentBackgroundActivityStartMode();
method public int getSplashScreenStyle();
- method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
+ method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed();
method public boolean isShareIdentityEnabled();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
@@ -4653,13 +4654,17 @@
method public android.app.ActivityOptions setLaunchBounds(@Nullable android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.app.ActivityOptions setLockTaskEnabled(boolean);
- method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+ method @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+ method @NonNull public android.app.ActivityOptions setPendingIntentBackgroundActivityStartMode(int);
method @NonNull public android.app.ActivityOptions setShareIdentityEnabled(boolean);
method @NonNull public android.app.ActivityOptions setSplashScreenStyle(int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ field public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; // 0x1
+ field public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2
+ field public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; // 0x0
}
public class AlarmManager {
@@ -4673,7 +4678,7 @@
method @RequiresPermission(android.Manifest.permission.SCHEDULE_EXACT_ALARM) public void setAlarmClock(@NonNull android.app.AlarmManager.AlarmClockInfo, @NonNull android.app.PendingIntent);
method public void setAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @NonNull android.app.PendingIntent);
- method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
+ method public void setExact(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExactAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
method public void setInexactRepeating(int, long, long, @NonNull android.app.PendingIntent);
method public void setRepeating(int, long, long, @NonNull android.app.PendingIntent);
@@ -8038,24 +8043,24 @@
field public static final int PACKAGE_POLICY_BLOCKLIST = 1; // 0x1
}
- public final class PolicyUpdateReason {
- ctor public PolicyUpdateReason(int);
- method public int getReasonCode();
- field public static final int REASON_CONFLICTING_ADMIN_POLICY = 0; // 0x0
- field public static final int REASON_UNKNOWN = -1; // 0xffffffff
+ public final class PolicyUpdateResult {
+ ctor public PolicyUpdateResult(int);
+ method public int getResultCode();
+ field public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1; // 0x1
+ field public static final int RESULT_FAILURE_UNKNOWN = -1; // 0xffffffff
+ field public static final int RESULT_SUCCESS = 0; // 0x0
}
public abstract class PolicyUpdatesReceiver extends android.content.BroadcastReceiver {
ctor public PolicyUpdatesReceiver();
- method public void onPolicyChanged(@NonNull android.content.Context, @NonNull String, @NonNull android.os.Bundle, @NonNull android.app.admin.TargetUser, @NonNull android.app.admin.PolicyUpdateReason);
- method public void onPolicySetResult(@NonNull android.content.Context, @NonNull String, @NonNull android.os.Bundle, @NonNull android.app.admin.TargetUser, int, @Nullable android.app.admin.PolicyUpdateReason);
+ method public void onPolicyChanged(@NonNull android.content.Context, @NonNull String, @NonNull android.os.Bundle, @NonNull android.app.admin.TargetUser, @NonNull android.app.admin.PolicyUpdateResult);
+ method public void onPolicySetResult(@NonNull android.content.Context, @NonNull String, @NonNull android.os.Bundle, @NonNull android.app.admin.TargetUser, @NonNull android.app.admin.PolicyUpdateResult);
method public final void onReceive(android.content.Context, android.content.Intent);
field public static final String ACTION_DEVICE_POLICY_CHANGED = "android.app.admin.action.DEVICE_POLICY_CHANGED";
field public static final String ACTION_DEVICE_POLICY_SET_RESULT = "android.app.admin.action.DEVICE_POLICY_SET_RESULT";
+ field public static final String EXTRA_INTENT_FILTER = "android.app.admin.extra.INTENT_FILTER";
field public static final String EXTRA_PACKAGE_NAME = "android.app.admin.extra.PACKAGE_NAME";
field public static final String EXTRA_PERMISSION_NAME = "android.app.admin.extra.PERMISSION_NAME";
- field public static final int POLICY_SET_RESULT_FAILURE = -1; // 0xffffffff
- field public static final int POLICY_SET_RESULT_SUCCESS = 0; // 0x0
}
public final class PreferentialNetworkServiceConfig implements android.os.Parcelable {
@@ -8645,6 +8650,8 @@
method public final void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, long, long);
method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
+ field public static final int JOB_END_NOTIFICATION_POLICY_DETACH = 0; // 0x0
+ field public static final int JOB_END_NOTIFICATION_POLICY_REMOVE = 1; // 0x1
field public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
@@ -9180,6 +9187,7 @@
method @Nullable public String getDeviceProfile();
method @Nullable public CharSequence getDisplayName();
method public int getId();
+ method public int getSystemDataSyncFlags();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationInfo> CREATOR;
}
@@ -9249,8 +9257,10 @@
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback);
method @Nullable public android.content.IntentSender buildAssociationCancellationIntent();
method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
+ method public void disableSystemDataSync(int, int);
method @Deprecated public void disassociate(@NonNull String);
method public void disassociate(int);
+ method public void enableSystemDataSync(int, int);
method @NonNull @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public java.util.List<android.companion.AssociationInfo> getAllAssociations();
method @Deprecated @NonNull public java.util.List<java.lang.String> getAssociations();
method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations();
@@ -9261,6 +9271,7 @@
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
field public static final String EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION";
field @Deprecated public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+ field public static final int FLAG_CALL_METADATA = 1; // 0x1
field public static final int RESULT_CANCELED = 0; // 0x0
field public static final int RESULT_DISCOVERY_TIMEOUT = 2; // 0x2
field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
@@ -10064,6 +10075,7 @@
field public static final String BATTERY_SERVICE = "batterymanager";
field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
field public static final int BIND_ADJUST_WITH_ACTIVITY = 128; // 0x80
+ field public static final int BIND_ALLOW_ACTIVITY_STARTS = 512; // 0x200
field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10
field public static final int BIND_AUTO_CREATE = 1; // 0x1
field public static final int BIND_DEBUG_UNBIND = 2; // 0x2
@@ -10705,6 +10717,7 @@
field public static final String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
field public static final String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
field public static final String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+ field public static final String EXTRA_CHOOSER_CUSTOM_ACTIONS = "android.intent.extra.CHOOSER_CUSTOM_ACTIONS";
field public static final String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";
field public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
field public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
@@ -12386,7 +12399,6 @@
field public static final String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
field public static final String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
- field public static final String FEATURE_SEAMLESS_REFRESH_RATE_SWITCHING = "android.software.seamless_refresh_rate_switching";
field public static final String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
field public static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen";
field public static final String FEATURE_SECURITY_MODEL_COMPATIBLE = "android.hardware.security.model.compatible";
@@ -33235,6 +33247,7 @@
field public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
field public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
field public static final String DISALLOW_FUN = "no_fun";
+ field public static final String DISALLOW_GRANT_ADMIN = "no_grant_admin";
field public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
field public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally";
@@ -39526,6 +39539,20 @@
package android.service.chooser {
+ public final class ChooserAction implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.app.PendingIntent getAction();
+ method @NonNull public android.graphics.drawable.Icon getIcon();
+ method @NonNull public CharSequence getLabel();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.chooser.ChooserAction> CREATOR;
+ }
+
+ public static final class ChooserAction.Builder {
+ ctor public ChooserAction.Builder(@NonNull android.graphics.drawable.Icon, @NonNull CharSequence, @NonNull android.app.PendingIntent);
+ method @NonNull public android.service.chooser.ChooserAction build();
+ }
+
@Deprecated public final class ChooserTarget implements android.os.Parcelable {
ctor @Deprecated public ChooserTarget(CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, @Nullable android.os.Bundle);
method @Deprecated public int describeContents();
@@ -40530,11 +40557,12 @@
method public void onLaunchVoiceAssistFromKeyguard();
method public void onPrepareToShowSession(@NonNull android.os.Bundle, int);
method public void onReady();
- method public void onShowSessionFailed();
+ method public void onShowSessionFailed(@NonNull android.os.Bundle);
method public void onShutdown();
method public void setDisabledShowContext(int);
method public final void setUiHints(@NonNull android.os.Bundle);
method public void showSession(android.os.Bundle, int);
+ field public static final String KEY_SHOW_SESSION_ID = "android.service.voice.SHOW_SESSION_ID";
field public static final String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final String SERVICE_META_DATA = "android.voice_interaction";
}
@@ -42965,7 +42993,7 @@
field public static final String KEY_SMS_MAX_RETRY_COUNT_INT = "imssms.sms_max_retry_count_int";
field public static final String KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT = "imssms.sms_max_retry_count_over_ims_int";
field public static final String KEY_SMS_OVER_IMS_FORMAT_INT = "imssms.sms_over_ims_format_int";
- field public static final String KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT = "imssms.sms_rover_ims_send_retry_delay_millis_int";
+ field public static final String KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT = "imssms.sms_over_ims_send_retry_delay_millis_int";
field public static final String KEY_SMS_OVER_IMS_SUPPORTED_BOOL = "imssms.sms_over_ims_supported_bool";
field public static final String KEY_SMS_OVER_IMS_SUPPORTED_RATS_INT_ARRAY = "imssms.sms_over_ims_supported_rats_int_array";
field public static final String KEY_SMS_RP_CAUSE_VALUES_TO_FALLBACK_INT_ARRAY = "imssms.sms_rp_cause_values_to_fallback_int_array";
@@ -49303,6 +49331,7 @@
method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
method public default int getBufferTransformHint();
method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
+ method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
method public default void setTouchableRegion(@Nullable android.graphics.Region);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 684b271..4e882d8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -209,6 +209,7 @@
field public static final String MIGRATE_HEALTH_CONNECT_DATA = "android.permission.MIGRATE_HEALTH_CONNECT_DATA";
field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
+ field public static final String MODIFY_AUDIO_SYSTEM_SETTINGS = "android.permission.MODIFY_AUDIO_SYSTEM_SETTINGS";
field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
field public static final String MODIFY_DAY_NIGHT_MODE = "android.permission.MODIFY_DAY_NIGHT_MODE";
field @Deprecated public static final String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
@@ -247,6 +248,7 @@
field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
field public static final String PROVISION_DEMO_DEVICE = "android.permission.PROVISION_DEMO_DEVICE";
field public static final String QUERY_ADMIN_POLICY = "android.permission.QUERY_ADMIN_POLICY";
+ field public static final String QUERY_CLONED_APPS = "android.permission.QUERY_CLONED_APPS";
field @Deprecated public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
field public static final String RADIO_SCAN_WITHOUT_LOCATION = "android.permission.RADIO_SCAN_WITHOUT_LOCATION";
@@ -541,8 +543,8 @@
public class AlarmManager {
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.PendingIntent, @Nullable android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler, @Nullable android.os.WorkSource);
- method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExact(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
- method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExactAndAllowWhileIdle(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setExact(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setExactAndAllowWhileIdle(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
method @RequiresPermission(android.Manifest.permission.SCHEDULE_PRIORITIZED_ALARM) public void setPrioritized(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.app.AlarmManager.OnAlarmListener);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setWindow(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
}
@@ -807,8 +809,9 @@
method @Nullable public android.content.IntentFilter getDeliveryGroupMatchingFilter();
method @Nullable public String getDeliveryGroupMatchingKey();
method public int getDeliveryGroupPolicy();
+ method public int getPendingIntentBackgroundActivityStartMode();
method public boolean isDeferUntilActive();
- method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
+ method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed();
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long);
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
@@ -817,7 +820,8 @@
method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
method public void setDontSendToRestrictedApps(boolean);
- method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+ method @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+ method @NonNull public android.app.BroadcastOptions setPendingIntentBackgroundActivityStartMode(int);
method public void setRequireAllOfPermissions(@Nullable String[]);
method public void setRequireCompatChange(long, boolean);
method public void setRequireNoneOfPermissions(@Nullable String[]);
@@ -1519,6 +1523,7 @@
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAncestralSerialNumber(long);
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
+ method @RequiresPermission(allOf={android.Manifest.permission.BACKUP, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public void setFrameworkSchedulingEnabled(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable CharSequence);
field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
@@ -3789,6 +3794,7 @@
field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
+ field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
field public static final int MATCH_INSTANT = 8388608; // 0x800000
@@ -6609,8 +6615,8 @@
}
public class AudioDeviceVolumeManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.VolumeInfo getDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public android.media.VolumeInfo getDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS}) public void setDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
}
public final class AudioFocusInfo implements android.os.Parcelable {
@@ -7500,6 +7506,7 @@
method public int getAudioFilterCount();
method public int getDemuxCount();
method public int getFilterCapabilities();
+ method @NonNull public int[] getFilterTypeCapabilityList();
method @NonNull @Size(5) public int[] getLinkCapabilities();
method public int getPcrFilterCount();
method public int getPesFilterCount();
@@ -7512,6 +7519,12 @@
method public boolean isTimeFilterSupported();
}
+ public class DemuxInfo {
+ ctor public DemuxInfo(int);
+ method public int getFilterTypes();
+ method public void setFilterTypes(int);
+ }
+
public class Descrambler implements java.lang.AutoCloseable {
method public int addPid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
method public void close();
@@ -7564,6 +7577,7 @@
method public void clearResourceLostListener();
method public void close();
method public void closeFrontend();
+ method public int configureDemux(@Nullable android.media.tv.tuner.DemuxInfo);
method public int connectCiCam(int);
method public int connectFrontendToCiCam(int);
method public int disconnectCiCam();
@@ -7571,6 +7585,7 @@
method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
method public long getAvSyncTime(int);
method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
+ method @Nullable public android.media.tv.tuner.DemuxInfo getCurrentDemuxInfo();
method @Nullable public String getCurrentFrontendHardwareInfo();
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
@@ -10403,6 +10418,7 @@
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public boolean isUserVisible();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int removeUserWhenPossible(@NonNull android.os.UserHandle, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public void setBootUser(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean someUserHasAccount(@NonNull String, @NonNull String);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 07750a5..8c64e40 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -528,6 +528,7 @@
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState();
method @RequiresPermission(allOf={android.Manifest.permission.MANAGE_DEVICE_ADMINS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwner(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, int);
@@ -897,6 +898,7 @@
method public boolean isDemo();
method public boolean isEnabled();
method public boolean isEphemeral();
+ method public boolean isForTesting();
method public boolean isFull();
method public boolean isGuest();
method public boolean isInitialized();
@@ -2025,6 +2027,7 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getBootUser();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 25483f2..48982b1 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3417,14 +3417,25 @@
}
/**
- * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the
- * specified display. This type of overlay should be used for content that does not need to
- * track the location and size of Views in the currently active app e.g. service configuration
- * or general service UI. To remove this overlay and free the associated resources, use
+ * Attaches a {@link android.view.SurfaceControl} containing an accessibility
+ * overlay to the
+ * specified display. This type of overlay should be used for content that does
+ * not need to
+ * track the location and size of Views in the currently active app e.g. service
+ * configuration
+ * or general service UI. To remove this overlay and free the associated
+ * resources, use
* <code> new SurfaceControl.Transaction().reparent(sc, null).apply();</code>.
+ * If the specified overlay has already been attached to the specified display
+ * this method does nothing.
+ * If the specified overlay has already been attached to a previous display this
+ * function will transfer the overlay to the new display.
+ * Services can attach multiple overlays. Use
+ * <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>.
+ * to coordinate the order of the overlays on screen.
*
* @param displayId the display to which the SurfaceControl should be attached.
- * @param sc the SurfaceControl containing the overlay content
+ * @param sc the SurfaceControl containing the overlay content
*/
public void attachAccessibilityOverlayToDisplay(int displayId, @NonNull SurfaceControl sc) {
Preconditions.checkNotNull(sc, "SurfaceControl cannot be null");
@@ -3436,18 +3447,30 @@
try {
connection.attachAccessibilityOverlayToDisplay(displayId, sc);
} catch (RemoteException re) {
- throw new RuntimeException(re);
+ re.rethrowFromSystemServer();
}
}
/**
- * Attaches an accessibility overlay {@link android.view.SurfaceControl} to the specified
- * window. This method should be used when you want the overlay to move and resize as the parent
- * window moves and resizes. To remove this overlay and free the associated resources, use
+ * Attaches an accessibility overlay {@link android.view.SurfaceControl} to the
+ * specified
+ * window. This method should be used when you want the overlay to move and
+ * resize as the parent
+ * window moves and resizes. To remove this overlay and free the associated
+ * resources, use
* <code> new SurfaceControl.Transaction().reparent(sc, null).apply();</code>.
+ * If the specified overlay has already been attached to the specified window
+ * this method does nothing.
+ * If the specified overlay has already been attached to a previous window this
+ * function will transfer the overlay to the new window.
+ * Services can attach multiple overlays. Use
+ * <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>.
+ * to coordinate the order of the overlays on screen.
*
- * @param accessibilityWindowId The window id, from {@link AccessibilityWindowInfo#getId()}.
- * @param sc the SurfaceControl containing the overlay content
+ * @param accessibilityWindowId The window id, from
+ * {@link AccessibilityWindowInfo#getId()}.
+ * @param sc the SurfaceControl containing the overlay
+ * content
*/
public void attachAccessibilityOverlayToWindow(
int accessibilityWindowId, @NonNull SurfaceControl sc) {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index dbdee07..821a23c 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,6 +16,8 @@
package android.accounts;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -891,15 +893,24 @@
* @return An {@link AccountManagerFuture} which resolves to a Boolean, true if the account
* exists and has all of the specified features.
*/
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS_FULL)
public AccountManagerFuture<Boolean> hasFeatures(final Account account,
final String[] features,
AccountManagerCallback<Boolean> callback, Handler handler) {
+ return hasFeaturesAsUser(account, features, callback, handler, mContext.getUserId());
+ }
+
+ private AccountManagerFuture<Boolean> hasFeaturesAsUser(
+ final Account account, final String[] features,
+ AccountManagerCallback<Boolean> callback, Handler handler, int userId) {
if (account == null) throw new IllegalArgumentException("account is null");
if (features == null) throw new IllegalArgumentException("features is null");
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
- mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
+ mService.hasFeatures(
+ mResponse, account, features, userId, mContext.getOpPackageName());
}
@Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
@@ -3319,7 +3330,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
public AccountManagerFuture<Bundle> finishSessionAsUser(
final Bundle sessionBundle,
final Activity activity,
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index a3a7b0c..08fb308 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -38,7 +38,7 @@
Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName);
Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features,
- String opPackageName);
+ int userId, String opPackageName);
void getAccountByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
in String[] features, String opPackageName);
void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a381fea..ce29937 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -311,6 +311,12 @@
@PermissionMethod
public abstract void enforceCallingPermission(@PermissionName String permission, String func);
+ /**
+ * Returns the current and target user ids as a {@link Pair}. Target user id will be
+ * {@link android.os.UserHandle#USER_NULL} if there is not an ongoing user switch.
+ */
+ public abstract Pair<Integer, Integer> getCurrentAndTargetUserIds();
+
/** Returns the current user id. */
public abstract int getCurrentUserId();
@@ -440,14 +446,14 @@
IApplicationThread resultToThread, IIntentReceiver resultTo, int resultCode,
String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
boolean serialized, boolean sticky, @UserIdInt int userId,
- boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
+ BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, @UserIdInt int userId,
- boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException;
+ BackgroundStartPrivileges backgroundStartPrivileges)
+ throws TransactionTooLargeException;
public abstract void disconnectActivityFromServices(Object connectionHolder);
public abstract void cleanUpServices(@UserIdInt int userId, ComponentName component,
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 2214c8e..57214e0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -2402,6 +2402,32 @@
}
+ /**
+ * Sets the mode for allowing or denying the senders privileges to start background activities
+ * to the PendingIntent.
+ *
+ * This is typically used in when executing {@link PendingIntent#send(Context, int, Intent,
+ * PendingIntent.OnFinished, Handler, String, Bundle)} or similar
+ * methods. A privileged sender of a PendingIntent should only grant
+ * {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOWED} if the PendingIntent is from a trusted source
+ * and/or executed on behalf the user.
+ */
+ public @NonNull ActivityOptions setPendingIntentBackgroundActivityStartMode(
+ @BackgroundActivityStartMode int state) {
+ super.setPendingIntentBackgroundActivityStartMode(state);
+ return this;
+ }
+
+ /**
+ * Get the mode for allowing or denying the senders privileges to start background activities
+ * to the PendingIntent.
+ *
+ * @see #setPendingIntentBackgroundActivityStartMode(int)
+ */
+ public @BackgroundActivityStartMode int getPendingIntentBackgroundActivityStartMode() {
+ return super.getPendingIntentBackgroundActivityStartMode();
+ }
+
/** @hide */
@Override
public String toString() {
diff --git a/core/java/android/app/BackgroundStartPrivileges.java b/core/java/android/app/BackgroundStartPrivileges.java
new file mode 100644
index 0000000..76c0ccf
--- /dev/null
+++ b/core/java/android/app/BackgroundStartPrivileges.java
@@ -0,0 +1,184 @@
+/*
+ * 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.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Privileges granted to a Process that allows it to execute starts from the background.
+ * @hide
+ */
+public class BackgroundStartPrivileges {
+ /** No privileges. */
+ public static final BackgroundStartPrivileges NONE = new BackgroundStartPrivileges(
+ false, false, null);
+ /** Allow activity starts (and implies allowing foreground service starts). */
+ public static final BackgroundStartPrivileges ALLOW_BAL = new BackgroundStartPrivileges(
+ true, true, null);
+ /** Allow foreground service starts. */
+ public static final BackgroundStartPrivileges ALLOW_FGS = new BackgroundStartPrivileges(
+ false, true, null);
+
+ private final boolean mAllowsBackgroundActivityStarts;
+ private final boolean mAllowsBackgroundForegroundServiceStarts;
+ private final IBinder mOriginatingToken;
+
+ private BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts,
+ boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken) {
+ Preconditions.checkArgument(
+ !allowsBackgroundActivityStarts || allowsBackgroundForegroundServiceStarts,
+ "backgroundActivityStarts implies bgFgServiceStarts");
+ mAllowsBackgroundActivityStarts = allowsBackgroundActivityStarts;
+ mAllowsBackgroundForegroundServiceStarts = allowsBackgroundForegroundServiceStarts;
+ mOriginatingToken = originatingToken;
+ }
+
+ /**
+ * Return a token that allows background activity starts and attributes it to a specific
+ * originatingToken.
+ */
+ public static BackgroundStartPrivileges allowBackgroundActivityStarts(
+ @Nullable IBinder originatingToken) {
+ if (originatingToken == null) {
+ // try to avoid creating new instances
+ return ALLOW_BAL;
+ }
+ return new BackgroundStartPrivileges(true, true, originatingToken);
+ }
+
+ /**
+ * Merge this {@link BackgroundStartPrivileges} with another {@link BackgroundStartPrivileges}.
+ *
+ * The resulting object will grant the union of the privileges of the merged objects.
+ * The originating tokens is retained only if both {@link BackgroundStartPrivileges} are the
+ * same.
+ *
+ * If one of the merged objects is {@link #NONE} then the other object is returned and the
+ * originating token is NOT cleared.
+ */
+ public @NonNull BackgroundStartPrivileges merge(@Nullable BackgroundStartPrivileges other) {
+ // shortcuts in case
+ if (other == NONE || other == null) {
+ return this;
+ }
+ if (this == NONE) {
+ return other;
+ }
+
+ boolean allowsBackgroundActivityStarts =
+ this.allowsBackgroundActivityStarts() || other.allowsBackgroundActivityStarts();
+ boolean allowsBackgroundFgsStarts =
+ this.allowsBackgroundFgsStarts() || other.allowsBackgroundFgsStarts();
+ if (this.mOriginatingToken == other.mOriginatingToken) {
+ // can reuse this?
+ if (this.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts
+ && this.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) {
+ return this;
+ }
+ // can reuse other?
+ if (other.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts
+ && other.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) {
+ return other;
+ }
+ // need to create a new instance (this should never happen)
+ return new BackgroundStartPrivileges(allowsBackgroundActivityStarts,
+ allowsBackgroundFgsStarts, this.mOriginatingToken);
+ } else {
+ // no originating token -> can use standard instance
+ if (allowsBackgroundActivityStarts) {
+ return ALLOW_BAL;
+ } else if (allowsBackgroundFgsStarts) {
+ return ALLOW_FGS;
+ } else {
+ return NONE;
+ }
+ }
+ }
+
+ /**
+ * Merge a collection of {@link BackgroundStartPrivileges} into a single token.
+ *
+ * The resulting object will grant the union of the privileges of the merged objects.
+ * The originating tokens is retained only if all {@link BackgroundStartPrivileges} are the
+ * same.
+ *
+ * If the list contains {@link #NONE}s these are ignored.
+ */
+ public static @NonNull BackgroundStartPrivileges merge(
+ @Nullable List<BackgroundStartPrivileges> list) {
+ if (list == null || list.isEmpty()) {
+ return NONE;
+ }
+ BackgroundStartPrivileges current = list.get(0);
+ for (int i = list.size(); i-- > 1; ) {
+ current = current.merge(list.get(i));
+ }
+ return current;
+ }
+
+ /**
+ * @return {@code true} if this grants the permission to start background activities from the
+ * background.
+ */
+ public boolean allowsBackgroundActivityStarts() {
+ return mAllowsBackgroundActivityStarts;
+ }
+
+ /**
+ * @return {@code true} this grants the permission to start foreground services from the
+ * background. */
+ public boolean allowsBackgroundFgsStarts() {
+ return mAllowsBackgroundForegroundServiceStarts;
+ }
+
+ /** @return true if this grants any privileges. */
+ public boolean allowsAny() {
+ return mAllowsBackgroundActivityStarts || mAllowsBackgroundForegroundServiceStarts;
+ }
+
+ /** Return true if this grants no privileges. */
+ public boolean allowsNothing() {
+ return !allowsAny();
+ }
+
+ /**
+ * Gets the originating token.
+ *
+ * The originating token is optional information that allows to trace back the origin of this
+ * object. Besides debugging, this is used to e.g. identify privileges created by the
+ * notification service.
+ */
+ public @Nullable IBinder getOriginatingToken() {
+ return mOriginatingToken;
+ }
+
+ @Override
+ public String toString() {
+ return "BackgroundStartPrivileges["
+ + "allowsBackgroundActivityStarts=" + mAllowsBackgroundActivityStarts
+ + ", allowsBackgroundForegroundServiceStarts="
+ + mAllowsBackgroundForegroundServiceStarts
+ + ", originatingToken=" + mOriginatingToken
+ + ']';
+ }
+}
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 5cf10d0..9ecf8ff 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -389,26 +389,6 @@
}
/**
- * Set PendingIntent activity is allowed to be started in the background if the caller
- * can start background activities.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
- public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
- super.setPendingIntentBackgroundActivityLaunchAllowed(allowed);
- }
-
- /**
- * Get PendingIntent activity is allowed to be started in the background if the caller
- * can start background activities.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
- public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
- return super.isPendingIntentBackgroundActivityLaunchAllowed();
- }
-
- /**
* Return {@link #setTemporaryAppAllowlist}.
* @hide
*/
@@ -937,6 +917,25 @@
}
/**
+ * Sets the mode for allowing or denying the senders privileges to start background activities
+ * to the PendingIntent.
+ *
+ * This is typically used when executing {@link PendingIntent#send(Bundle)} or similar
+ * methods. A privileged sender of a PendingIntent should only grant
+ * MODE_BACKGROUND_ACTIVITY_START_ALLOWED if the PendingIntent is from a trusted source and/or
+ * executed on behalf the user.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @Override // to narrow down the return type
+ public BroadcastOptions setPendingIntentBackgroundActivityStartMode(int state) {
+ super.setPendingIntentBackgroundActivityStartMode(state);
+ return this;
+ }
+
+ /**
* Returns the created options as a Bundle, which can be passed to
* {@link android.content.Context#sendBroadcast(android.content.Intent)
* Context.sendBroadcast(Intent)} and related methods.
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index 74db39f..3776369 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -16,21 +16,22 @@
package android.app;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.os.Bundle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
+ * Base class for {@link ActivityOptions} and {@link BroadcastOptions}.
* @hide
*/
public class ComponentOptions {
/**
- * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED.
- * @hide
- **/
- public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true;
-
- /**
* PendingIntent caller allows activity start even if PendingIntent creator is in background.
* This only works if the PendingIntent caller is allowed to start background activities,
* for example if it's in the foreground, or has BAL permission.
@@ -52,10 +53,23 @@
*/
public static final String KEY_INTERACTIVE = "android:component.isInteractive";
- private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+ private @Nullable Boolean mPendingIntentBalAllowed = null;
private boolean mPendingIntentBalAllowedByPermission = false;
private boolean mIsInteractive = false;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = {
+ MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED,
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
+ MODE_BACKGROUND_ACTIVITY_START_DENIED})
+ public @interface BackgroundActivityStartMode {}
+ /** No explicit value chosen. The system will decide whether to grant privileges. */
+ public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0;
+ /** Allow the {@link PendingIntent} to use the background activity start privileges. */
+ public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1;
+ /** Deny the {@link PendingIntent} to use the background activity start privileges. */
+ public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2;
+
ComponentOptions() {
}
@@ -63,12 +77,16 @@
// If the remote side sent us bad parcelables, they won't get the
// results they want, which is their loss.
opts.setDefusable(true);
- setPendingIntentBackgroundActivityLaunchAllowed(
- opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
- PENDING_INTENT_BAL_ALLOWED_DEFAULT));
+
+ boolean pendingIntentBalAllowedIsSetExplicitly =
+ opts.containsKey(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED);
+ if (pendingIntentBalAllowedIsSetExplicitly) {
+ mPendingIntentBalAllowed =
+ opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED);
+ }
setPendingIntentBackgroundActivityLaunchAllowedByPermission(
- opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
- false));
+ opts.getBoolean(
+ KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, false));
mIsInteractive = opts.getBoolean(KEY_INTERACTIVE, false);
}
@@ -97,20 +115,74 @@
/**
* Set PendingIntent activity is allowed to be started in the background if the caller
* can start background activities.
+ *
+ * @deprecated use #setPendingIntentBackgroundActivityStartMode(int) to set the full range
+ * of states
*/
- public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
+ @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
mPendingIntentBalAllowed = allowed;
}
/**
- * Get PendingIntent activity is allowed to be started in the background if the caller
- * can start background activities.
+ * Get PendingIntent activity is allowed to be started in the background if the caller can start
+ * background activities.
+ *
+ * @deprecated use {@link #getPendingIntentBackgroundActivityStartMode()} since for apps
+ * targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or higher this value might
+ * not match the actual behavior if the value was not explicitly set.
*/
- public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+ @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+ if (mPendingIntentBalAllowed == null) {
+ // cannot return null, so return the value used up to API level 33 for compatibility
+ return true;
+ }
return mPendingIntentBalAllowed;
}
/**
+ * Sets the mode for allowing or denying the senders privileges to start background activities
+ * to the PendingIntent.
+ *
+ * This is typically used in when executing {@link PendingIntent#send(Bundle)} or similar
+ * methods. A privileged sender of a PendingIntent should only grant
+ * {@link #MODE_BACKGROUND_ACTIVITY_START_ALLOWED} if the PendingIntent is from a trusted source
+ * and/or executed on behalf the user.
+ */
+ public @NonNull ComponentOptions setPendingIntentBackgroundActivityStartMode(
+ @BackgroundActivityStartMode int state) {
+ switch (state) {
+ case MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED:
+ mPendingIntentBalAllowed = null;
+ break;
+ case MODE_BACKGROUND_ACTIVITY_START_ALLOWED:
+ mPendingIntentBalAllowed = true;
+ break;
+ case MODE_BACKGROUND_ACTIVITY_START_DENIED:
+ mPendingIntentBalAllowed = false;
+ break;
+ default:
+ throw new IllegalArgumentException(state + " is not valid");
+ }
+ return this;
+ }
+
+ /**
+ * Gets the mode for allowing or denying the senders privileges to start background activities
+ * to the PendingIntent.
+ *
+ * @see #setPendingIntentBackgroundActivityStartMode(int)
+ */
+ public @BackgroundActivityStartMode int getPendingIntentBackgroundActivityStartMode() {
+ if (mPendingIntentBalAllowed == null) {
+ return MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+ } else if (mPendingIntentBalAllowed) {
+ return MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+ } else {
+ return MODE_BACKGROUND_ACTIVITY_START_DENIED;
+ }
+ }
+
+ /**
* Set PendingIntent activity can be launched from background if caller has BAL permission.
* @hide
*/
@@ -129,7 +201,9 @@
public Bundle toBundle() {
Bundle b = new Bundle();
- b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
+ if (mPendingIntentBalAllowed != null) {
+ b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
+ }
if (mPendingIntentBalAllowedByPermission) {
b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
mPendingIntentBalAllowedByPermission);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1633073..11584cc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.SET_TIME;
import static android.Manifest.permission.SET_TIME_ZONE;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
@@ -3963,6 +3964,9 @@
* Called by a device owner, a profile owner of an organization-owned device or the system to
* get the Memory Tagging Extension (MTE) policy
*
+ * <a href="https://source.android.com/docs/security/test/memory-safety/arm-mte">
+ * Learn more about MTE</a>
+ *
* @throws SecurityException if caller is not device owner or profile owner of org-owned device
* or system uid, or if called on a parent instance
* @return the currently set MTE policy
@@ -3985,6 +3989,7 @@
*/
public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+ // TODO: Expose this as SystemAPI once we add the query API
/**
* @hide
*/
@@ -4011,7 +4016,22 @@
/**
* @hide
*/
- public static final String USER_CONTROL_DISABLED_PACKAGES = "userControlDisabledPackages";
+ public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
+ "userControlDisabledPackages";
+
+
+ // TODO: Expose this as SystemAPI once we add the query API
+ /**
+ * @hide
+ */
+ public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
+ "persistentPreferredActivity";
+
+ // TODO: Expose this as SystemAPI once we add the query API
+ /**
+ * @hide
+ */
+ public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
/**
* This object is a single place to tack on invalidation and disable calls. All
@@ -4186,7 +4206,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
public boolean packageHasActiveAdmins(String packageName) {
return packageHasActiveAdmins(packageName, myUserId());
}
@@ -8743,7 +8763,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@RequiresPermission(allOf = {
android.Manifest.permission.MANAGE_DEVICE_ADMINS,
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+ INTERACT_ACROSS_USERS_FULL
})
public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing,
int userHandle) {
@@ -10654,7 +10674,7 @@
*/
@UserHandleAware
@RequiresPermission(allOf = {
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ INTERACT_ACROSS_USERS_FULL,
android.Manifest.permission.MANAGE_USERS
}, conditional = true)
public @Nullable List<String> getPermittedInputMethods() {
@@ -14845,7 +14865,7 @@
* @hide
*/
@RequiresPermission(anyOf = {
- permission.INTERACT_ACROSS_USERS_FULL,
+ INTERACT_ACROSS_USERS_FULL,
permission.INTERACT_ACROSS_USERS
}, conditional = true)
public boolean isPackageAllowedToAccessCalendar(@NonNull String packageName) {
@@ -14877,7 +14897,7 @@
* @hide
*/
@RequiresPermission(anyOf = {
- permission.INTERACT_ACROSS_USERS_FULL,
+ INTERACT_ACROSS_USERS_FULL,
permission.INTERACT_ACROSS_USERS
})
public @Nullable Set<String> getCrossProfileCalendarPackages() {
@@ -14970,7 +14990,7 @@
* @hide
*/
@RequiresPermission(anyOf = {
- permission.INTERACT_ACROSS_USERS_FULL,
+ INTERACT_ACROSS_USERS_FULL,
permission.INTERACT_ACROSS_USERS,
permission.INTERACT_ACROSS_PROFILES
})
@@ -16154,6 +16174,23 @@
}
/**
+ * Reset cache for {@link #shouldAllowBypassingDevicePolicyManagementRoleQualification}.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+ public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() {
+ if (mService != null) {
+ try {
+ mService.resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* @return {@code true} if bypassing the device policy management role qualification is allowed
* with the current state of the device.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 20695ca..aebeaf0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -575,6 +575,7 @@
void resetStrings(in List<String> stringIds);
ParcelableResource getString(String stringId);
+ void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState();
boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
List<UserHandle> getPolicyManagedProfiles(in UserHandle userHandle);
diff --git a/core/java/android/app/admin/PolicyUpdateReason.java b/core/java/android/app/admin/PolicyUpdateReason.java
deleted file mode 100644
index 97d282d..0000000
--- a/core/java/android/app/admin/PolicyUpdateReason.java
+++ /dev/null
@@ -1,74 +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.app.admin;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Class containing the reason a policy (set from {@link DevicePolicyManager}) hasn't been enforced
- * (passed in to {@link PolicyUpdatesReceiver#onPolicySetResult}) or has changed (passed in to
- * {@link PolicyUpdatesReceiver#onPolicyChanged}).
- */
-public final class PolicyUpdateReason {
-
- /**
- * Reason code to indicate that the policy has not been enforced or has changed for an unknown
- * reason.
- */
- public static final int REASON_UNKNOWN = -1;
-
- /**
- * Reason code to indicate that the policy has not been enforced or has changed because another
- * admin has set a conflicting policy on the device.
- */
- public static final int REASON_CONFLICTING_ADMIN_POLICY = 0;
-
- /**
- * Reason codes for {@link #getReasonCode()}.
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "REASON_" }, value = {
- REASON_UNKNOWN,
- REASON_CONFLICTING_ADMIN_POLICY,
- })
- public @interface ReasonCode {}
-
- private final int mReasonCode;
-
- /**
- * Constructor for {@code PolicyUpdateReason} that takes in a reason code describing why the
- * policy has changed.
- *
- * @param reasonCode Describes why the policy has changed.
- */
- public PolicyUpdateReason(@ReasonCode int reasonCode) {
- this.mReasonCode = reasonCode;
- }
-
- /**
- * Returns reason code for why a policy hasn't been applied or has changed.
- */
- @ReasonCode
- public int getReasonCode() {
- return mReasonCode;
- }
-}
diff --git a/core/java/android/app/admin/PolicyUpdateResult.java b/core/java/android/app/admin/PolicyUpdateResult.java
new file mode 100644
index 0000000..9e13e00
--- /dev/null
+++ b/core/java/android/app/admin/PolicyUpdateResult.java
@@ -0,0 +1,82 @@
+/*
+ * 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.admin;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class containing the reason for the policy (set from {@link DevicePolicyManager}) update (e.g.
+ * success, failure reasons, etc.). This is passed in to
+ * {@link PolicyUpdatesReceiver#onPolicySetResult}) and
+ * {@link PolicyUpdatesReceiver#onPolicyChanged}).
+ */
+public final class PolicyUpdateResult {
+
+ /**
+ * Result code to indicate that the policy has not been enforced or has changed for an unknown
+ * reason.
+ */
+ public static final int RESULT_FAILURE_UNKNOWN = -1;
+
+ /**
+ * Result code to indicate that the policy has been changed to the desired value set by
+ * the admin.
+ */
+ public static final int RESULT_SUCCESS = 0;
+
+ /**
+ * Result code to indicate that the policy has not been enforced or has changed because another
+ * admin has set a conflicting policy on the device.
+ */
+ public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1;
+
+ /**
+ * Reason codes for {@link #getResultCode()}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "RESULT_" }, value = {
+ RESULT_FAILURE_UNKNOWN,
+ RESULT_SUCCESS,
+ RESULT_FAILURE_CONFLICTING_ADMIN_POLICY
+ })
+ public @interface ResultCode {}
+
+ private final int mResultCode;
+
+ /**
+ * Constructor for {@code PolicyUpdateReason} that takes in a result code describing why the
+ * policy has changed.
+ *
+ * @param resultCode Describes why the policy has changed.
+ */
+ public PolicyUpdateResult(@ResultCode int resultCode) {
+ this.mResultCode = resultCode;
+ }
+
+ /**
+ * Returns result code describing why the policy has changed.
+ */
+ @ResultCode
+ public int getResultCode() {
+ return mResultCode;
+ }
+}
diff --git a/core/java/android/app/admin/PolicyUpdatesReceiver.java b/core/java/android/app/admin/PolicyUpdatesReceiver.java
index f7216e7..67de04c 100644
--- a/core/java/android/app/admin/PolicyUpdatesReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdatesReceiver.java
@@ -17,9 +17,7 @@
package android.app.admin;
import android.annotation.BroadcastBehavior;
-import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -27,8 +25,6 @@
import android.os.Bundle;
import android.util.Log;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -50,31 +46,6 @@
private static String TAG = "PolicyUpdatesReceiver";
/**
- * Result code passed in to {@link #onPolicySetResult} to indicate that the policy has been
- * set successfully.
- */
- public static final int POLICY_SET_RESULT_SUCCESS = 0;
-
- /**
- * Result code passed in to {@link #onPolicySetResult} to indicate that the policy has NOT been
- * set, a {@link PolicyUpdateReason} will be passed in to {@link #onPolicySetResult} to indicate
- * the reason.
- */
- public static final int POLICY_SET_RESULT_FAILURE = -1;
-
- /**
- * Result codes passed in to {@link #onPolicySetResult}.
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "POLICY_SET_RESULT_" }, value = {
- POLICY_SET_RESULT_SUCCESS,
- POLICY_SET_RESULT_FAILURE,
- })
- public @interface ResultCode {}
-
- /**
* Action for a broadcast sent to admins to communicate back the result of setting a policy in
* {@link DevicePolicyManager}.
*
@@ -125,6 +96,14 @@
"android.app.admin.extra.PERMISSION_NAME";
/**
+ * An {@link android.content.IntentFilter} extra holding the intent filter the policy relates
+ * to, (see {@link PolicyUpdatesReceiver#onPolicyChanged} and
+ * {@link PolicyUpdatesReceiver#onPolicySetResult})
+ */
+ public static final String EXTRA_INTENT_FILTER =
+ "android.app.admin.extra.INTENT_FILTER";
+
+ /**
* @hide
*/
public static final String EXTRA_POLICY_CHANGED_KEY =
@@ -144,14 +123,8 @@
/**
* @hide
*/
- public static final String EXTRA_POLICY_SET_RESULT_KEY =
- "android.app.admin.extra.POLICY_SET_RESULT_KEY";
-
- /**
- * @hide
- */
- public static final String EXTRA_POLICY_UPDATE_REASON_KEY =
- "android.app.admin.extra.POLICY_UPDATE_REASON_KEY";
+ public static final String EXTRA_POLICY_UPDATE_RESULT_KEY =
+ "android.app.admin.extra.POLICY_UPDATE_RESULT_KEY";
/**
* @hide
@@ -172,7 +145,7 @@
case ACTION_DEVICE_POLICY_SET_RESULT:
Log.i(TAG, "Received ACTION_DEVICE_POLICY_SET_RESULT");
onPolicySetResult(context, getPolicyKey(intent), getPolicyExtraBundle(intent),
- getTargetUser(intent), getPolicyResult(intent), getFailureReason(intent));
+ getTargetUser(intent), getPolicyChangedReason(intent));
break;
case ACTION_DEVICE_POLICY_CHANGED:
Log.i(TAG, "Received ACTION_DEVICE_POLICY_CHANGED");
@@ -197,17 +170,6 @@
/**
* @hide
*/
- @ResultCode
- static int getPolicyResult(Intent intent) {
- if (!intent.hasExtra(EXTRA_POLICY_SET_RESULT_KEY)) {
- throw new IllegalArgumentException("Result has to be provided.");
- }
- return intent.getIntExtra(EXTRA_POLICY_SET_RESULT_KEY, POLICY_SET_RESULT_FAILURE);
- }
-
- /**
- * @hide
- */
@NonNull
static Bundle getPolicyExtraBundle(Intent intent) {
Bundle bundle = intent.getBundleExtra(EXTRA_POLICY_BUNDLE_KEY);
@@ -217,22 +179,14 @@
/**
* @hide
*/
- @Nullable
- static PolicyUpdateReason getFailureReason(Intent intent) {
- if (getPolicyResult(intent) != POLICY_SET_RESULT_FAILURE) {
- return null;
- }
- return getPolicyChangedReason(intent);
- }
-
- /**
- * @hide
- */
@NonNull
- static PolicyUpdateReason getPolicyChangedReason(Intent intent) {
+ static PolicyUpdateResult getPolicyChangedReason(Intent intent) {
+ if (!intent.hasExtra(EXTRA_POLICY_UPDATE_RESULT_KEY)) {
+ throw new IllegalArgumentException("PolicyUpdateResult has to be provided.");
+ }
int reasonCode = intent.getIntExtra(
- EXTRA_POLICY_UPDATE_REASON_KEY, PolicyUpdateReason.REASON_UNKNOWN);
- return new PolicyUpdateReason(reasonCode);
+ EXTRA_POLICY_UPDATE_RESULT_KEY, PolicyUpdateResult.RESULT_FAILURE_UNKNOWN);
+ return new PolicyUpdateResult(reasonCode);
}
/**
@@ -268,19 +222,18 @@
* Each policy will document the required additional params if
* needed.
* @param targetUser The {@link TargetUser} which this policy relates to.
- * @param result Indicates whether the policy has been set successfully,
- * (see {@link PolicyUpdatesReceiver#POLICY_SET_RESULT_SUCCESS} and
- * {@link PolicyUpdatesReceiver#POLICY_SET_RESULT_FAILURE}).
- * @param reason Indicates the reason the policy failed to apply, {@code null} if the policy was
- * applied successfully.
+ * @param policyUpdateResult Indicates whether the policy has been set successfully
+ * ({@link PolicyUpdateResult#RESULT_SUCCESS}) or the reason it
+ * failed to apply (e.g.
+ * {@link PolicyUpdateResult#RESULT_FAILURE_CONFLICTING_ADMIN_POLICY},
+ * etc).
*/
public void onPolicySetResult(
@NonNull Context context,
@NonNull String policyKey,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
- @ResultCode int result,
- @Nullable PolicyUpdateReason reason) {}
+ @NonNull PolicyUpdateResult policyUpdateResult) {}
// TODO(b/260847505): Add javadocs to explain which DPM APIs are supported
// TODO(b/261430877): Add javadocs to explain when will this get triggered
@@ -302,12 +255,17 @@
* Each policy will document the required additional params if
* needed.
* @param targetUser The {@link TargetUser} which this policy relates to.
- * @param reason Indicates the reason the policy value has changed.
+ * @param policyUpdateResult Indicates the reason the policy value has changed
+ * (e.g. {@link PolicyUpdateResult#RESULT_SUCCESS} if the policy has
+ * changed to the value set by the admin,
+ * {@link PolicyUpdateResult#RESULT_FAILURE_CONFLICTING_ADMIN_POLICY}
+ * if the policy has changed because another admin has set a
+ * conflicting policy, etc)
*/
public void onPolicyChanged(
@NonNull Context context,
@NonNull String policyKey,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
- @NonNull PolicyUpdateReason reason) {}
+ @NonNull PolicyUpdateResult policyUpdateResult) {}
}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index bad282e..e750f49 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,7 +16,6 @@
package android.app.backup;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -38,8 +37,6 @@
import android.util.Log;
import android.util.Pair;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -410,6 +407,36 @@
}
/**
+ * Enable/disable the framework backup scheduling entirely for the context user. When disabled,
+ * no Key/Value or Full backup jobs will be scheduled by the Android framework.
+ *
+ * <p>Note: This does not disable backups: only their scheduling is affected and backups can
+ * still be triggered manually.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method. If the
+ * context user is different from the calling user, then the caller must additionally hold the
+ * android.permission.INTERACT_ACROSS_USERS_FULL permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {android.Manifest.permission.BACKUP,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true)
+ public void setFrameworkSchedulingEnabled(boolean isEnabled) {
+ checkServiceBinder();
+ if (sService == null) {
+ Log.e(TAG, "setFrameworkSchedulingEnabled() couldn't connect");
+ return;
+ }
+
+ try {
+ sService.setFrameworkSchedulingEnabledForUser(mContext.getUserId(), isEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setFrameworkSchedulingEnabled() couldn't connect");
+ }
+ }
+
+ /**
* Report whether the backup mechanism is currently enabled.
*
* @hide
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index aeb4987..041c2a7 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -155,6 +155,22 @@
*/
void setBackupEnabledForUser(int userId, boolean isEnabled);
+
+ /**
+ * Enable/disable the framework backup scheduling entirely. When disabled, no Key/Value or Full
+ * backup jobs will be scheduled by the Android framework.
+ *
+ * <p>Note: This does not disable backups: only their scheduling is affected and backups can
+ * still be triggered manually.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method. If
+ * {@code userId} is different from the calling user id, then the caller must additionally hold
+ * the android.permission.INTERACT_ACROSS_USERS_FULL permission.
+ *
+ * @param userId The user for which backup scheduling should be enabled/disabled.
+ */
+ void setFrameworkSchedulingEnabledForUser(int userId, boolean isEnabled);
+
/**
* {@link android.app.backup.IBackupManager.setBackupEnabledForUser} for the calling user id.
*/
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 5fd39fe..0958a806 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -56,6 +56,7 @@
private final boolean mSelfManaged;
private final boolean mNotifyOnDeviceNearby;
+ private final int mSystemDataSyncFlags;
/**
* Indicates that the association has been revoked (removed), but we keep the association
@@ -73,7 +74,6 @@
/**
* Creates a new Association.
- * Only to be used by the CompanionDeviceManagerService.
*
* @hide
*/
@@ -81,7 +81,7 @@
@Nullable MacAddress macAddress, @Nullable CharSequence displayName,
@Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice,
boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked,
- long timeApprovedMs, long lastTimeConnectedMs) {
+ long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) {
if (id <= 0) {
throw new IllegalArgumentException("Association ID should be greater than 0");
}
@@ -105,6 +105,7 @@
mRevoked = revoked;
mTimeApprovedMs = timeApprovedMs;
mLastTimeConnectedMs = lastTimeConnectedMs;
+ mSystemDataSyncFlags = systemDataSyncFlags;
}
/**
@@ -221,6 +222,16 @@
}
/**
+ * @return Enabled system data sync flags set via
+ * {@link CompanionDeviceManager#enableSystemDataSync(int, int)} and
+ * {@link CompanionDeviceManager#disableSystemDataSync(int, int)}.
+ * Or by default all flags are 1 (enabled).
+ */
+ public int getSystemDataSyncFlags() {
+ return mSystemDataSyncFlags;
+ }
+
+ /**
* Utility method for checking if the association represents a device with the given MAC
* address.
*
@@ -287,6 +298,7 @@
+ ", mLastTimeConnectedMs=" + (
mLastTimeConnectedMs == Long.MAX_VALUE
? LAST_TIME_CONNECTED_NONE : new Date(mLastTimeConnectedMs))
+ + ", mSystemDataSyncFlags=" + mSystemDataSyncFlags
+ '}';
}
@@ -306,14 +318,15 @@
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
&& Objects.equals(mDisplayName, that.mDisplayName)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
- && Objects.equals(mAssociatedDevice, that.mAssociatedDevice);
+ && Objects.equals(mAssociatedDevice, that.mAssociatedDevice)
+ && mSystemDataSyncFlags == that.mSystemDataSyncFlags;
}
@Override
public int hashCode() {
return Objects.hash(mId, mUserId, mPackageName, mDeviceMacAddress, mDisplayName,
mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked,
- mTimeApprovedMs, mLastTimeConnectedMs);
+ mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags);
}
@Override
@@ -338,6 +351,7 @@
dest.writeBoolean(mRevoked);
dest.writeLong(mTimeApprovedMs);
dest.writeLong(mLastTimeConnectedMs);
+ dest.writeInt(mSystemDataSyncFlags);
}
private AssociationInfo(@NonNull Parcel in) {
@@ -356,6 +370,7 @@
mRevoked = in.readBoolean();
mTimeApprovedMs = in.readLong();
mLastTimeConnectedMs = in.readLong();
+ mSystemDataSyncFlags = in.readInt();
}
@NonNull
@@ -390,27 +405,24 @@
return new Builder(info);
}
- /**
- * @hide
- */
+ /** @hide */
public static final class Builder implements NonActionableBuilder {
@NonNull
private final AssociationInfo mOriginalInfo;
private boolean mNotifyOnDeviceNearby;
private boolean mRevoked;
private long mLastTimeConnectedMs;
+ private int mSystemDataSyncFlags;
private Builder(@NonNull AssociationInfo info) {
mOriginalInfo = info;
mNotifyOnDeviceNearby = info.mNotifyOnDeviceNearby;
mRevoked = info.mRevoked;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
+ mSystemDataSyncFlags = info.mSystemDataSyncFlags;
}
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@Override
@NonNull
public Builder setLastTimeConnected(long lastTimeConnectedMs) {
@@ -423,10 +435,7 @@
return this;
}
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@Override
@NonNull
public Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby) {
@@ -434,10 +443,7 @@
return this;
}
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@Override
@NonNull
public Builder setRevoked(boolean revoked) {
@@ -445,9 +451,15 @@
return this;
}
- /**
- * @hide
- */
+ /** @hide */
+ @Override
+ @NonNull
+ public Builder setSystemDataSyncFlags(int flags) {
+ mSystemDataSyncFlags = flags;
+ return this;
+ }
+
+ /** @hide */
@NonNull
public AssociationInfo build() {
return new AssociationInfo(
@@ -462,7 +474,8 @@
mNotifyOnDeviceNearby,
mRevoked,
mOriginalInfo.mTimeApprovedMs,
- mLastTimeConnectedMs
+ mLastTimeConnectedMs,
+ mSystemDataSyncFlags
);
}
}
@@ -480,25 +493,20 @@
* @hide
*/
public interface NonActionableBuilder {
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@NonNull
Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby);
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@NonNull
Builder setLastTimeConnected(long lastTimeConnectedMs);
- /**
- * Should only be used by the CompanionDeviceManagerService.
- * @hide
- */
+ /** @hide */
@NonNull
Builder setRevoked(boolean revoked);
+
+ /** @hide */
+ @NonNull
+ Builder setSystemDataSyncFlags(int flags);
}
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index d31124d..baa88e4 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -166,6 +166,19 @@
*/
public static final String REASON_CANCELED = "canceled";
+ /** @hide */
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_CALL_METADATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DataSyncTypes {}
+
+ /**
+ * Used by {@link #enableSystemDataSync(int, int)}}.
+ * Sync call metadata like muting, ending and silencing a call.
+ *
+ */
+ public static final int FLAG_CALL_METADATA = 1;
/**
* A device, returned in the activity result of the {@link IntentSender} received in
@@ -468,6 +481,49 @@
}
}
+ /**
+ * <p>Enable system data sync (it only supports call metadata sync for now).
+ * By default all supported system data types are enabled.</p>
+ *
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
+ * @param associationId id of the device association.
+ * @param flags system data types to be enabled.
+ */
+ public void enableSystemDataSync(int associationId, @DataSyncTypes int flags) {
+ if (!checkFeaturePresent()) {
+ return;
+ }
+
+ try {
+ mService.enableSystemDataSync(associationId, flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * <p>Disable system data sync (it only supports call metadata sync for now).
+ * By default all supported system data types are enabled.</p>
+ *
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
+ * @param associationId id of the device association.
+ * @param flags system data types to be disabled.
+ */
+ public void disableSystemDataSync(int associationId, @DataSyncTypes int flags) {
+ if (!checkFeaturePresent()) {
+ return;
+ }
+
+ try {
+ mService.disableSystemDataSync(associationId, flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* <p>Calling this API requires a uses-feature
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 24ef52b..010aa8f 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -84,4 +84,8 @@
boolean isCompanionApplicationBound(String packageName, int userId);
PendingIntent buildAssociationCancellationIntent(in String callingPackage, int userId);
+
+ void enableSystemDataSync(int associationId, int flags);
+
+ void disableSystemDataSync(int associationId, int flags);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c8d48c1..a58cac3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -278,6 +278,7 @@
BIND_IMPORTANT,
BIND_ADJUST_WITH_ACTIVITY,
BIND_NOT_PERCEPTIBLE,
+ BIND_ALLOW_ACTIVITY_STARTS,
BIND_INCLUDE_CAPABILITIES,
BIND_SHARED_ISOLATED_PROCESS
})
@@ -382,6 +383,15 @@
public static final int BIND_NOT_PERCEPTIBLE = 0x00000100;
/**
+ * Flag for {@link #bindService}: If binding from an app that is visible, the bound service is
+ * allowed to start an activity from background. This was the default behavior before SDK
+ * version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}. Since then, the default
+ * behavior changed to disallow the bound service to start a background activity even if the app
+ * bound to it is in foreground, unless this flag is specified when binding.
+ */
+ public static final int BIND_ALLOW_ACTIVITY_STARTS = 0X000000200;
+
+ /**
* Flag for {@link #bindService}: If binding from an app that has specific capabilities
* due to its foreground state such as an activity or foreground service, then this flag will
* allow the bound app to get the same capabilities, as long as it has the required permissions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 77cf49d..5714032 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5819,10 +5819,9 @@
/**
* A Parcelable[] of {@link ChooserAction} objects to provide the Android Sharesheet with
* app-specific actions to be presented to the user when invoking {@link #ACTION_CHOOSER}.
- * @hide
*/
public static final String EXTRA_CHOOSER_CUSTOM_ACTIONS =
- "android.intent.extra.EXTRA_CHOOSER_CUSTOM_ACTIONS";
+ "android.intent.extra.CHOOSER_CUSTOM_ACTIONS";
/**
* Optional argument to be used with {@link #ACTION_CHOOSER}.
@@ -5833,7 +5832,7 @@
* @hide
*/
public static final String EXTRA_CHOOSER_PAYLOAD_RESELECTION_ACTION =
- "android.intent.extra.EXTRA_CHOOSER_PAYLOAD_RESELECTION_ACTION";
+ "android.intent.extra.CHOOSER_PAYLOAD_RESELECTION_ACTION";
/**
* An {@code ArrayList} of {@code String} annotations describing content for
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0e37c87..047f8c1 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -276,6 +276,8 @@
void clearPackagePersistentPreferredActivities(String packageName, int userId);
+ void clearPersistentPreferredActivity(in IntentFilter filter, int userId);
+
void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
int sourceUserId, int targetUserId, int flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 900454d..1a6f6b8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -783,6 +783,7 @@
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
+ MATCH_CLONE_PROFILE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResolveInfoFlagsBits {}
@@ -1113,6 +1114,19 @@
public static final int MATCH_DIRECT_BOOT_AUTO = 0x10000000;
/**
+ * {@link ResolveInfo} flag: allow matching components across clone profile
+ * <p>
+ * This flag is used only for query and not resolution, the default behaviour would be to
+ * restrict querying across clone profile. This flag would be honored only if caller have
+ * permission {@link Manifest.permission.QUERY_CLONED_APPS}.
+ *
+ * @hide
+ * <p>
+ */
+ @SystemApi
+ public static final int MATCH_CLONE_PROFILE = 0x20000000;
+
+ /**
* {@link PackageInfo} flag: return all attributions declared in the package manifest
*/
public static final int GET_ATTRIBUTIONS = 0x80000000;
@@ -3011,14 +3025,6 @@
"android.software.virtualization_framework";
/**
- * Feature for {@link #getSystemAvailableFeatures()} and {@link #hasSystemFeature(String)}.
- * This feature indicates whether device supports seamless refresh rate switching.
- */
- @SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_SEAMLESS_REFRESH_RATE_SWITCHING
- = "android.software.seamless_refresh_rate_switching";
-
- /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan
* implementation on this device is hardware accelerated, and the Vulkan native API will
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 2be0323..44747fa 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -171,6 +171,16 @@
public static final int FLAG_MAIN = 0x00004000;
/**
+ * Indicates that this user was created for the purposes of testing.
+ *
+ * <p>These users are subject to removal during tests and should not be used on actual devices
+ * used by humans.
+ *
+ * @hide
+ */
+ public static final int FLAG_FOR_TESTING = 0x00008000;
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = "FLAG_", value = {
@@ -188,7 +198,8 @@
FLAG_SYSTEM,
FLAG_PROFILE,
FLAG_EPHEMERAL_ON_CREATE,
- FLAG_MAIN
+ FLAG_MAIN,
+ FLAG_FOR_TESTING
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserInfoFlag {
@@ -369,6 +380,12 @@
return (flags & FLAG_EPHEMERAL) == FLAG_EPHEMERAL;
}
+ /** @hide */
+ @TestApi
+ public boolean isForTesting() {
+ return (flags & FLAG_FOR_TESTING) == FLAG_FOR_TESTING;
+ }
+
public boolean isInitialized() {
return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED;
}
diff --git a/core/java/android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException.java b/core/java/android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException.java
index 41f2f9c..b86b97c 100644
--- a/core/java/android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException.java
+++ b/core/java/android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException.java
@@ -17,7 +17,7 @@
package android.database.sqlite;
/**
- * Thrown if the the bind or column parameter index is out of range
+ * Thrown if the bind or column parameter index is out of range.
*/
public class SQLiteBindOrColumnIndexOutOfRangeException extends SQLiteException {
public SQLiteBindOrColumnIndexOutOfRangeException() {}
diff --git a/core/java/android/database/sqlite/SQLiteDiskIOException.java b/core/java/android/database/sqlite/SQLiteDiskIOException.java
index 01b2069..152d90a 100644
--- a/core/java/android/database/sqlite/SQLiteDiskIOException.java
+++ b/core/java/android/database/sqlite/SQLiteDiskIOException.java
@@ -17,7 +17,7 @@
package android.database.sqlite;
/**
- * An exception that indicates that an IO error occured while accessing the
+ * Indicates that an IO error occurred while accessing the
* SQLite database file.
*/
public class SQLiteDiskIOException extends SQLiteException {
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index e2dedd6..da847a8 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -398,6 +398,23 @@
* except that it uses {@link java.util.concurrent.Executor} as an argument
* instead of {@link android.os.Handler}.</p>
*
+ * <p>Note: If the order between some availability callbacks matters, the implementation of the
+ * executor should handle those callbacks in the same thread to maintain the callbacks' order.
+ * Some examples are:</p>
+ *
+ * <ul>
+ *
+ * <li>{@link AvailabilityCallback#onCameraAvailable} and
+ * {@link AvailabilityCallback#onCameraUnavailable} of the same camera ID.</li>
+ *
+ * <li>{@link AvailabilityCallback#onCameraAvailable} or
+ * {@link AvailabilityCallback#onCameraUnavailable} of a logical multi-camera, and {@link
+ * AvailabilityCallback#onPhysicalCameraUnavailable} or
+ * {@link AvailabilityCallback#onPhysicalCameraAvailable} of its physical
+ * cameras.</li>
+ *
+ * </ul>
+ *
* @param executor The executor which will be used to invoke the callback.
* @param callback the new callback to send camera availability notices to
*
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 42803a1..b333f5a 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -50,6 +50,8 @@
import android.view.Display;
import android.view.Surface;
+import com.android.internal.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -1323,6 +1325,22 @@
}
/**
+ * Returns whether device supports seamless refresh rate switching.
+ *
+ * Match content frame rate setting has three options: seamless, non-seamless and never.
+ * The seamless option does nothing if the device does not support seamless refresh rate
+ * switching. This API is used in such a case to hide the seamless option.
+ *
+ * @see DisplayManager#setRefreshRateSwitchingType
+ * @see DisplayManager#getMatchContentFrameRateUserPreference
+ * @hide
+ */
+ public boolean supportsSeamlessRefreshRateSwitching() {
+ return mContext.getResources().getBoolean(
+ R.bool.config_supportsSeamlessRefreshRateSwitching);
+ }
+
+ /**
* Sets the refresh rate switching type.
* This matches {@link android.provider.Settings.Secure.MATCH_CONTENT_FRAME_RATE}
*
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index d55367f..ed6a88f 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -223,11 +223,13 @@
final SomeArgs args = (SomeArgs) msg.obj;
final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
inputMethod.showSoftInputWithToken(
msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
}
args.recycle();
return;
@@ -236,11 +238,13 @@
final SomeArgs args = (SomeArgs) msg.obj;
final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
if (isValid(inputMethod, target, "DO_HIDE_SOFT_INPUT")) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
(IBinder) args.arg1, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
}
args.recycle();
return;
@@ -428,7 +432,7 @@
@Override
public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
int flags, ResultReceiver resultReceiver) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
flags, showInputToken, resultReceiver, statsToken));
}
@@ -437,7 +441,7 @@
@Override
public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
int flags, ResultReceiver resultReceiver) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT,
flags, hideInputToken, resultReceiver, statsToken));
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 872414a..ee9d8a4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -896,7 +896,8 @@
@MainThread
@Override
public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
- ImeTracker.get().onProgress(mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
+ ImeTracker.forLogging().onProgress(
+ mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
if (DEBUG) Log.v(TAG, "hideSoftInput()");
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
&& !mSystemCallingHideSoftInput) {
@@ -950,7 +951,8 @@
@MainThread
@Override
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
- ImeTracker.get().onProgress(mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
+ ImeTracker.forLogging().onProgress(
+ mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
if (DEBUG) Log.v(TAG, "showSoftInput()");
// TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
@@ -966,11 +968,11 @@
null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
- ImeTracker.get().onProgress(mCurStatsToken,
+ ImeTracker.forLogging().onProgress(mCurStatsToken,
ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
showWindow(true);
} else {
- ImeTracker.get().onFailed(mCurStatsToken,
+ ImeTracker.forLogging().onFailed(mCurStatsToken,
ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
}
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
@@ -2979,7 +2981,7 @@
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
null /* icProto */);
- ImeTracker.get().onProgress(mCurStatsToken,
+ ImeTracker.forLogging().onProgress(mCurStatsToken,
ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
mPrivOps.applyImeVisibilityAsync(setVisible
? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 547d406..083b4f6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2904,6 +2904,15 @@
public abstract long getMobileRadioEnergyConsumptionUC();
/**
+ * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device
+ * power measurement data.
+ * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+ *
+ * {@hide}
+ */
+ public abstract long getPhoneEnergyConsumptionUC();
+
+ /**
* Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3b4e8cd..d1d3315 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -142,4 +142,8 @@
long getUserStartRealtime();
long getUserUnlockRealtime();
boolean setUserEphemeral(int userId, boolean enableEphemeral);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})")
+ void setBootUser(int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})")
+ int getBootUser();
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b016c781..62d8fb2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -323,6 +323,24 @@
public static final String DISALLOW_WIFI_TETHERING = "no_wifi_tethering";
/**
+ * Specifies if a user is disallowed from being granted admin privileges.
+ *
+ * <p>This restriction limits ability of other admin users to grant admin
+ * privileges to selected user.
+ *
+ * <p>This restriction has no effect in a mode that does not allow multiple admins.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_GRANT_ADMIN = "no_grant_admin";
+
+ /**
* Specifies if users are disallowed from sharing Wi-Fi for admin configured networks.
*
* <p>Device owner and profile owner can set this restriction.
@@ -5671,6 +5689,40 @@
}
}
+ /**
+ * Sets the user who should be in the foreground when boot completes. This should be called
+ * during boot, and the provided user must be a full user (i.e. not a profile).
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
+ public void setBootUser(@NonNull UserHandle bootUser) {
+ try {
+ mService.setBootUser(bootUser.getIdentifier());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the user who should be in the foreground when boot completes.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
+ @SuppressWarnings("[AndroidFrameworkContextUserId]")
+ public @NonNull UserHandle getBootUser() {
+ try {
+ return UserHandle.of(mService.getBootUser());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
/* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */
private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9a848af..b510fad 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8660,6 +8660,12 @@
public static final String BACKUP_AUTO_RESTORE = "backup_auto_restore";
/**
+ * Controls whether framework backup scheduling is enabled.
+ * @hide
+ */
+ public static final String BACKUP_SCHEDULING_ENABLED = "backup_scheduling_enabled";
+
+ /**
* Indicates whether settings backup has been fully provisioned.
* Type: int ( 0 = unprovisioned, 1 = fully provisioned )
* @hide
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 0fb9f57..b0e847c 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -166,7 +166,7 @@
}
/**
- * Description of an event that occured after the latest call to
+ * Description of an event that occurred after the latest call to
* {@link FillCallback#onSuccess(FillResponse)}.
*/
public static final class Event {
diff --git a/core/java/android/service/chooser/ChooserAction.java b/core/java/android/service/chooser/ChooserAction.java
index 3010049..cabf4ed 100644
--- a/core/java/android/service/chooser/ChooserAction.java
+++ b/core/java/android/service/chooser/ChooserAction.java
@@ -27,11 +27,9 @@
/**
* A ChooserAction is an app-defined action that can be provided to the Android Sharesheet to
- * be shown to the user when {@link android.content.Intent.ACTION_CHOOSER} is invoked.
+ * be shown to the user when {@link android.content.Intent#ACTION_CHOOSER} is invoked.
*
- * @see android.content.Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS
- * @see android.content.Intent.EXTRA_CHOOSER_PAYLOAD_RESELECTION_ACTION
- * @hide
+ * @see android.content.Intent#EXTRA_CHOOSER_CUSTOM_ACTIONS
*/
public final class ChooserAction implements Parcelable {
private final Icon mIcon;
@@ -88,6 +86,7 @@
return "ChooserAction {" + "label=" + mLabel + ", intent=" + mAction + "}";
}
+ @NonNull
public static final Parcelable.Creator<ChooserAction> CREATOR =
new Creator<ChooserAction>() {
@Override
@@ -137,6 +136,7 @@
* object.
* @return the built action
*/
+ @NonNull
public ChooserAction build() {
return new ChooserAction(mIcon, mLabel, mAction);
}
diff --git a/core/java/android/service/quickaccesswallet/OWNERS b/core/java/android/service/quickaccesswallet/OWNERS
new file mode 100644
index 0000000..232ee02
--- /dev/null
+++ b/core/java/android/service/quickaccesswallet/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 802986
+asc@google.com
+juliacr@google.com
+steell@google.com
diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl
index efae5c1..6a54606 100644
--- a/core/java/android/service/voice/IVoiceInteractionService.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionService.aidl
@@ -31,5 +31,5 @@
void getActiveServiceSupportedActions(in List<String> voiceActions,
in IVoiceActionCheckCallback callback);
void prepareToShowSession(in Bundle args, int flags);
- void showSessionFailed();
+ void showSessionFailed(in Bundle args);
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index a5156ef..df739e3 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -95,6 +95,20 @@
public static final String SERVICE_META_DATA = "android.voice_interaction";
/**
+ * Bundle key used to specify the id when the system prepares to show session. It increases for
+ * each request.
+ * <p>
+ * Type: int
+ * </p>
+ * @see #showSession(Bundle, int)
+ * @see #onPrepareToShowSession(Bundle, int)
+ * @see #onShowSessionFailed(Bundle)
+ * @see VoiceInteractionSession#onShow(Bundle, int)
+ * @see VoiceInteractionSession#show(Bundle, int)
+ */
+ public static final String KEY_SHOW_SESSION_ID = "android.service.voice.SHOW_SESSION_ID";
+
+ /**
* For apps targeting Build.VERSION_CODES.TRAMISU and above, implementors of this
* service can create multiple AlwaysOnHotwordDetector instances in parallel. They will
* also e ale to create a single SoftwareHotwordDetector in parallel with any other
@@ -170,10 +184,10 @@
}
@Override
- public void showSessionFailed() {
+ public void showSessionFailed(@NonNull Bundle args) {
Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
VoiceInteractionService::onShowSessionFailed,
- VoiceInteractionService.this));
+ VoiceInteractionService.this, args));
}
};
@@ -205,9 +219,10 @@
* bind the session service.
*
* @param args The arguments that were supplied to {@link #showSession(Bundle, int)}.
+ * It always includes {@link #KEY_SHOW_SESSION_ID}.
* @param flags The show flags originally provided to {@link #showSession(Bundle, int)}.
* @see #showSession(Bundle, int)
- * @see #onShowSessionFailed()
+ * @see #onShowSessionFailed(Bundle)
* @see VoiceInteractionSession#onShow(Bundle, int)
* @see VoiceInteractionSession#show(Bundle, int)
*/
@@ -217,12 +232,14 @@
/**
* Called when the show session failed. E.g. When the system bound the session service failed.
*
+ * @param args Additional info about the show session attempt that failed. For now, includes
+ * {@link #KEY_SHOW_SESSION_ID}.
* @see #showSession(Bundle, int)
* @see #onPrepareToShowSession(Bundle, int)
* @see VoiceInteractionSession#onShow(Bundle, int)
* @see VoiceInteractionSession#show(Bundle, int)
*/
- public void onShowSessionFailed() {
+ public void onShowSessionFailed(@NonNull Bundle args) {
}
/**
@@ -719,8 +736,8 @@
private void onHotwordDetectorDestroyed(@NonNull HotwordDetector detector) {
synchronized (mLock) {
- if (mActiveVisualQueryDetector!= null &&
- detector == mActiveVisualQueryDetector.getInitializationDelegate()) {
+ if (mActiveVisualQueryDetector != null
+ && detector == mActiveVisualQueryDetector.getInitializationDelegate()) {
mActiveVisualQueryDetector = null;
}
mActiveDetectors.remove(detector);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 2c70229..d55fede 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1763,7 +1763,8 @@
* @param args The arguments that were supplied to
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
* Some example keys include : "invocation_type", "invocation_phone_state",
- * "invocation_time_ms", Intent.EXTRA_TIME ("android.intent.extra.TIME") indicating timing
+ * {@link VoiceInteractionService#KEY_SHOW_SESSION_ID}, "invocation_time_ms",
+ * Intent.EXTRA_TIME ("android.intent.extra.TIME") indicating timing
* in milliseconds of the KeyEvent that triggered Assistant and
* Intent.EXTRA_ASSIST_INPUT_DEVICE_ID (android.intent.extra.ASSIST_INPUT_DEVICE_ID)
* referring to the device that sent the request.
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 7f45b38..196bac2 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -24,6 +24,7 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
+import android.text.method.OffsetMapping;
import android.text.style.ReplacementSpan;
import android.text.style.UpdateLayout;
import android.text.style.WrapTogetherSpan;
@@ -1095,10 +1096,27 @@
}
public void beforeTextChanged(CharSequence s, int where, int before, int after) {
- // Intentionally empty
+ final DynamicLayout dynamicLayout = mLayout.get();
+ if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
+ final OffsetMapping transformedText = (OffsetMapping) dynamicLayout.mDisplay;
+ if (mTransformedTextUpdate == null) {
+ mTransformedTextUpdate = new OffsetMapping.TextUpdate(where, before, after);
+ } else {
+ mTransformedTextUpdate.where = where;
+ mTransformedTextUpdate.before = before;
+ mTransformedTextUpdate.after = after;
+ }
+ transformedText.originalToTransformed(mTransformedTextUpdate);
+ }
}
public void onTextChanged(CharSequence s, int where, int before, int after) {
+ final DynamicLayout dynamicLayout = mLayout.get();
+ if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
+ where = mTransformedTextUpdate.where;
+ before = mTransformedTextUpdate.before;
+ after = mTransformedTextUpdate.after;
+ }
reflow(s, where, before, after);
}
@@ -1106,14 +1124,34 @@
// Intentionally empty
}
+ /**
+ * Reflow the {@link DynamicLayout} at the given range from {@code start} to the
+ * {@code end}.
+ * If the display text in this {@link DynamicLayout} is a {@link OffsetMapping} instance
+ * (which means it's also a transformed text), it will transform the given range first and
+ * then reflow.
+ */
+ private void transformAndReflow(Spannable s, int start, int end) {
+ final DynamicLayout dynamicLayout = mLayout.get();
+ if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
+ final OffsetMapping transformedText = (OffsetMapping) dynamicLayout.mDisplay;
+ start = transformedText.originalToTransformed(start,
+ OffsetMapping.MAP_STRATEGY_CHARACTER);
+ end = transformedText.originalToTransformed(end,
+ OffsetMapping.MAP_STRATEGY_CHARACTER);
+ }
+ reflow(s, start, end - start, end - start);
+ }
+
public void onSpanAdded(Spannable s, Object o, int start, int end) {
- if (o instanceof UpdateLayout)
- reflow(s, start, end - start, end - start);
+ if (o instanceof UpdateLayout) {
+ transformAndReflow(s, start, end);
+ }
}
public void onSpanRemoved(Spannable s, Object o, int start, int end) {
if (o instanceof UpdateLayout)
- reflow(s, start, end - start, end - start);
+ transformAndReflow(s, start, end);
}
public void onSpanChanged(Spannable s, Object o, int start, int end, int nstart, int nend) {
@@ -1123,12 +1161,13 @@
// instead of causing an exception
start = 0;
}
- reflow(s, start, end - start, end - start);
- reflow(s, nstart, nend - nstart, nend - nstart);
+ transformAndReflow(s, start, end);
+ transformAndReflow(s, nstart, nend);
}
}
private WeakReference<DynamicLayout> mLayout;
+ private OffsetMapping.TextUpdate mTransformedTextUpdate;
}
@Override
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index d3367d0..37474e5 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -68,6 +68,9 @@
@Override
protected boolean left(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendLeft(buffer, layout);
@@ -78,6 +81,9 @@
@Override
protected boolean right(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendRight(buffer, layout);
@@ -88,6 +94,9 @@
@Override
protected boolean up(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendUp(buffer, layout);
@@ -98,6 +107,9 @@
@Override
protected boolean down(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendDown(buffer, layout);
@@ -108,6 +120,9 @@
@Override
protected boolean pageUp(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
final boolean selecting = isSelecting(buffer);
final int targetY = getCurrentLineTop(buffer, layout) - getPageHeight(widget);
@@ -132,6 +147,9 @@
@Override
protected boolean pageDown(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
final boolean selecting = isSelecting(buffer);
final int targetY = getCurrentLineTop(buffer, layout) + getPageHeight(widget);
@@ -176,6 +194,9 @@
@Override
protected boolean lineStart(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendToLeftEdge(buffer, layout);
@@ -186,6 +207,9 @@
@Override
protected boolean lineEnd(TextView widget, Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendToRightEdge(buffer, layout);
@@ -224,6 +248,9 @@
@Override
public boolean previousParagraph(@NonNull TextView widget, @NonNull Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendToParagraphStart(buffer);
@@ -234,6 +261,9 @@
@Override
public boolean nextParagraph(@NonNull TextView widget, @NonNull Spannable buffer) {
+ if (widget.isOffsetMappingAvailable()) {
+ return false;
+ }
final Layout layout = widget.getLayout();
if (isSelecting(buffer)) {
return Selection.extendToParagraphEnd(buffer);
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 01989d5..9a120d5 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -440,8 +440,9 @@
private boolean deleteLine(View view, Editable content) {
if (view instanceof TextView) {
- final Layout layout = ((TextView) view).getLayout();
- if (layout != null) {
+ final TextView textView = (TextView) view;
+ final Layout layout = textView.getLayout();
+ if (layout != null && !textView.isOffsetMappingAvailable()) {
final int line = layout.getLineForOffset(Selection.getSelectionStart(content));
final int start = layout.getLineStart(line);
final int end = layout.getLineEnd(line);
diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java
index c544c41..dae978e 100644
--- a/core/java/android/text/method/LinkMovementMethod.java
+++ b/core/java/android/text/method/LinkMovementMethod.java
@@ -100,6 +100,10 @@
private boolean action(int what, TextView widget, Spannable buffer) {
Layout layout = widget.getLayout();
+ if (widget.isOffsetMappingAvailable()) {
+ // The text in the layout is transformed and has OffsetMapping, don't do anything.
+ return false;
+ }
int padding = widget.getTotalPaddingTop() +
widget.getTotalPaddingBottom();
diff --git a/core/java/android/text/method/OffsetMapping.java b/core/java/android/text/method/OffsetMapping.java
new file mode 100644
index 0000000..fcf3de6
--- /dev/null
+++ b/core/java/android/text/method/OffsetMapping.java
@@ -0,0 +1,170 @@
+/*
+ * 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.text.method;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The interface for the index mapping information of a transformed text returned by
+ * {@link TransformationMethod}. This class is mainly used to support the
+ * {@link TransformationMethod} that alters the text length.
+ * @hide
+ */
+public interface OffsetMapping {
+ /**
+ * The mapping strategy for a character offset.
+ *
+ * @see #originalToTransformed(int, int)
+ * @see #transformedToOriginal(int, int)
+ */
+ int MAP_STRATEGY_CHARACTER = 0;
+
+ /**
+ * The mapping strategy for a cursor position.
+ *
+ * @see #originalToTransformed(int, int)
+ * @see #transformedToOriginal(int, int)
+ */
+ int MAP_STRATEGY_CURSOR = 1;
+
+ @IntDef(prefix = { "MAP_STRATEGY" }, value = {
+ MAP_STRATEGY_CHARACTER,
+ MAP_STRATEGY_CURSOR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MapStrategy {}
+
+ /**
+ * Map an offset at original text to the offset at transformed text. <br/>
+ *
+ * This function must be a monotonically non-decreasing function. In other words, if the offset
+ * advances at the original text, the offset at the transformed text must advance or stay there.
+ * <br/>
+ *
+ * Depending on the mapping strategy, a same offset can be mapped differently. For example,
+ * <pre>
+ * Original: ABCDE
+ * Transformed: ABCXDE ('X' is introduced due to the transformation.)
+ * </pre>
+ * Let's check the offset 3, which is the offset of the character 'D'.
+ * If we want to map the character offset 3, it should be mapped to index 4.
+ * If we want to map the cursor offset 3 (the offset of the character before which the cursor is
+ * placed), it's unclear if the mapped cursor is before 'X' or after 'X'.
+ * This depends on how the transformed text reacts an insertion at offset 3 in the original
+ * text. Assume character 'V' is insert at offset 3 in the original text, and the original text
+ * become "ABCVDE". The transformed text can be:
+ * <pre>
+ * 1) "ABCVXDE"
+ * or
+ * 2) "ABCXVDE"
+ * </pre>
+ * In the first case, the offset 3 should be mapped to 3 (before 'X'). And in the second case,
+ * the offset should be mapped to 4 (after 'X').<br/>
+ *
+ * In some cases, a character offset at the original text doesn't have a proper corresponding
+ * offset at the transformed text. For example:
+ * <pre>
+ * Original: ABCDE
+ * Transformed: ABDE ('C' is deleted due to the transformation.)
+ * </pre>
+ * The character offset 2 can be mapped either to offset 2 or 3, but neither is meaningful. For
+ * convenience, it MUST map to the next offset (offset 3 in this case), or the
+ * transformedText.length() if there is no valid character to map.
+ * This is mandatory when the map strategy is {@link #MAP_STRATEGY_CHARACTER}, but doesn't
+ * apply for other map strategies.
+ *
+ * @param offset the offset at the original text. It's normally equal to or less than the
+ * originalText.length(). When {@link #MAP_STRATEGY_CHARACTER} is passed, it must
+ * be less than originalText.length(). For convenience, it's also allowed to be
+ * negative, which represents an invalid offset. When the given offset is
+ * negative, this method should return it as it is.
+ * @param strategy the mapping strategy. Depending on its value, the same offset can be mapped
+ * differently.
+ * @return the mapped offset at the transformed text, must be equal to or less than the
+ * transformedText.length().
+ *
+ * @see #transformedToOriginal(int, int)
+ */
+ int originalToTransformed(int offset, @MapStrategy int strategy);
+
+ /**
+ * Map an offset at transformed text to the offset at original text. This is the reverse method
+ * of {@link #originalToTransformed(int, int)}. <br/>
+ * This function must be a monotonically non-decreasing function. In other words, if the offset
+ * advances at the original text, the offset at the transformed text must advance or stay there.
+ * <br/>
+ * Similar to the {@link #originalToTransformed(int, int)} if a character offset doesn't have a
+ * corresponding offset at the transformed text, it MUST return the value as the previous
+ * offset. This is mandatory when the map strategy is {@link #MAP_STRATEGY_CHARACTER},
+ * but doesn't apply for other map strategies.
+ *
+ * @param offset the offset at the transformed text. It's normally equal to or less than the
+ * transformedText.length(). When {@link #MAP_STRATEGY_CHARACTER} is passed, it
+ * must be less than transformedText.length(). For convenience, it's also allowed
+ * to be negative, which represents an invalid offset. When the given offset is
+ * negative, this method should return it as it is.
+ * @param strategy the mapping strategy. Depending on its value, the same offset can be mapped
+ * differently.
+ * @return the mapped offset at the original text, must be equal to or less than the
+ * original.length().
+ *
+ * @see #originalToTransformed(int, int)
+ */
+ int transformedToOriginal(int offset, @MapStrategy int strategy);
+
+ /**
+ * Map a text update in the original text to an update the transformed text.
+ * This method used to determine how the transformed text is updated in response to an
+ * update in the original text. It is always called before the original text being changed.
+ *
+ * The main usage of this method is to update text layout incrementally. So it should report
+ * the range where text needs to be laid out again.
+ *
+ * @param textUpdate the {@link TextUpdate} object containing the text update information on
+ * the original text. The transformed text update information will also be
+ * stored at this object.
+ */
+ void originalToTransformed(TextUpdate textUpdate);
+
+ /**
+ * The class that stores the text update information that from index <code>where</code>,
+ * <code>after</code> characters will replace the old text that has length <code>before</code>.
+ */
+ class TextUpdate {
+ /** The start index of the text update range, inclusive */
+ public int where;
+ /** The length of the replaced old text. */
+ public int before;
+ /** The length of the new text that replaces the old text. */
+ public int after;
+
+ /**
+ * Creates a {@link TextUpdate} object.
+ * @param where the start index of the text update range.
+ * @param before the length of the replaced old text.
+ * @param after the length of the new text that replaces the old text.
+ */
+ public TextUpdate(int where, int before, int after) {
+ this.where = where;
+ this.before = before;
+ this.after = after;
+ }
+ }
+}
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 787ffb7..dc06671 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -156,14 +156,14 @@
* AttachedSurfaceControl. This includes SurfaceView, and an example usage may
* be to ensure that SurfaceView with {@link android.view.SurfaceView#setZOrderOnTop}
* are cropped to a region not including the app bar.
- *
+ * <p>
* This cropped is expressed in terms of insets in window-space. Negative insets
* are considered invalid and will produce an exception. Insets of zero will produce
* the same result as if this function had never been called.
*
* @param insets The insets in each direction by which to bound the children
* expressed in window-space.
- * @hide
+ * @throws IllegalArgumentException If negative insets are provided.
*/
default void setChildBoundingInsets(@NonNull Rect insets) {
}
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index e89be47..3e84153 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -123,7 +123,7 @@
// TODO: ResultReceiver for IME.
// TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW);
if (getControl() == null) {
@@ -164,12 +164,13 @@
// - we do already have one, but we have control and use the passed in token
// for the insets animation already.
if (statsToken == null || getControl() != null) {
- statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(),
+ statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
+ Process.myUid(),
ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
}
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN);
getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8e8e28a..c992450 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -26,6 +26,7 @@
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
+import static android.view.inputmethod.ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -35,6 +36,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -60,6 +63,7 @@
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.ImeTracker.InputMethodJankContext;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -186,6 +190,14 @@
@Nullable
String getRootViewTitle();
+ /**
+ * @return the context related to the rootView.
+ */
+ @Nullable
+ default Context getRootViewContext() {
+ return null;
+ }
+
/** @see ViewRootImpl#dipToPx */
int dipToPx(int dips);
@@ -306,7 +318,7 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
- @interface AnimationType {
+ public @interface AnimationType {
}
/**
@@ -321,6 +333,27 @@
/** Logging listener. */
private WindowInsetsAnimationControlListener mLoggingListener;
+ /** Context for {@link android.view.inputmethod.ImeTracker.ImeJankTracker} to monitor jank. */
+ private final InputMethodJankContext mJankContext = new InputMethodJankContext() {
+ @Override
+ public Context getDisplayContext() {
+ return mHost != null ? mHost.getRootViewContext() : null;
+ }
+
+ @Override
+ public SurfaceControl getTargetSurfaceControl() {
+ final InsetsSourceConsumer imeSourceConsumer = mSourceConsumers.get(ITYPE_IME);
+ final InsetsSourceControl imeSourceControl =
+ imeSourceConsumer != null ? imeSourceConsumer.getControl() : null;
+ return imeSourceControl != null ? imeSourceControl.getLeash() : null;
+ }
+
+ @Override
+ public String getHostPackageName() {
+ return mHost != null ? mHost.getRootViewContext().getPackageName() : null;
+ }
+ };
+
/**
* The default implementation of listener, to be used by InsetsController and InsetsPolicy to
* animate insets.
@@ -338,6 +371,7 @@
private final boolean mDisable;
private final int mFloatingImeBottomInset;
private final WindowInsetsAnimationControlListener mLoggingListener;
+ private final InputMethodJankContext mInputMethodJankContext;
private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
new ThreadLocal<AnimationHandler>() {
@@ -351,7 +385,8 @@
public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
@InsetsType int requestedTypes, @Behavior int behavior, boolean disable,
- int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener) {
+ int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener,
+ @Nullable InputMethodJankContext jankContext) {
mShow = show;
mHasAnimationCallbacks = hasAnimationCallbacks;
mRequestedTypes = requestedTypes;
@@ -360,6 +395,7 @@
mDisable = disable;
mFloatingImeBottomInset = floatingImeBottomInset;
mLoggingListener = loggingListener;
+ mInputMethodJankContext = jankContext;
}
@Override
@@ -406,10 +442,26 @@
+ insetsFraction);
});
mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (mInputMethodJankContext == null) return;
+ ImeTracker.forJank().onRequestAnimation(
+ mInputMethodJankContext,
+ mShow ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
+ !mHasAnimationCallbacks);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mInputMethodJankContext == null) return;
+ ImeTracker.forJank().onCancelAnimation();
+ }
@Override
public void onAnimationEnd(Animator animation) {
onAnimationFinish();
+ if (mInputMethodJankContext == null) return;
+ ImeTracker.forJank().onFinishAnimation();
}
});
if (!mHasAnimationCallbacks) {
@@ -873,7 +925,7 @@
/**
* @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
- * int, SparseIntArray)
+ * int, android.util.SparseIntArray)
*/
@VisibleForTesting
public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
@@ -981,7 +1033,7 @@
public void show(@InsetsType int types) {
ImeTracker.Token statsToken = null;
if ((types & ime()) != 0) {
- statsToken = ImeTracker.get().onRequestShow(null /* component */,
+ statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
}
@@ -1006,6 +1058,9 @@
}
// Handle pending request ready in case there was one set.
if (fromIme && mPendingImeControlRequest != null) {
+ if ((types & Type.ime()) != 0) {
+ ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
+ }
handlePendingControlRequest(statsToken);
return;
}
@@ -1028,7 +1083,7 @@
"show ignored for type: %d animType: %d requestedVisible: %s",
type, animationType, requestedVisible));
if (isImeAnimation) {
- ImeTracker.get().onCancelled(statsToken,
+ ImeTracker.forLogging().onCancelled(statsToken,
ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
}
continue;
@@ -1036,16 +1091,21 @@
if (fromIme && animationType == ANIMATION_TYPE_USER) {
// App is already controlling the IME, don't cancel it.
if (isImeAnimation) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
}
continue;
}
if (isImeAnimation) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
}
typesReady |= type;
}
if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady);
+ if (fromIme && (typesReady & Type.ime()) != 0) {
+ ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
+ }
applyAnimation(typesReady, true /* show */, fromIme, statsToken);
}
@@ -1074,7 +1134,7 @@
public void hide(@InsetsType int types) {
ImeTracker.Token statsToken = null;
if ((types & ime()) != 0) {
- statsToken = ImeTracker.get().onRequestHide(null /* component */,
+ statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
}
@@ -1123,13 +1183,14 @@
// no-op: already hidden or animating out (because window visibility is
// applied before starting animation).
if (isImeAnimation) {
- ImeTracker.get().onCancelled(statsToken,
+ ImeTracker.forLogging().onCancelled(statsToken,
ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
}
continue;
}
if (isImeAnimation) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
}
typesReady |= type;
}
@@ -1201,8 +1262,19 @@
@AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
if ((types & mTypesBeingCancelled) != 0) {
+ final boolean monitoredAnimation =
+ animationType == ANIMATION_TYPE_SHOW || animationType == ANIMATION_TYPE_HIDE;
+ if (monitoredAnimation && (types & Type.ime()) != 0) {
+ if (animationType == ANIMATION_TYPE_SHOW) {
+ ImeTracker.forLatency().onShowCancelled(statsToken,
+ PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+ } else {
+ ImeTracker.forLatency().onHideCancelled(statsToken,
+ PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+ }
+ }
throw new IllegalStateException("Cannot start a new insets animation of "
+ Type.toString(types)
+ " while an existing " + Type.toString(mTypesBeingCancelled)
@@ -1214,7 +1286,7 @@
types &= ~mDisabledUserAnimationInsetsTypes;
if ((disabledTypes & ime()) != 0) {
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
if (fromIme && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) {
@@ -1235,7 +1307,8 @@
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
if (DEBUG) Log.d(TAG, "controlAnimation types: " + types);
mLastStartedAnimTypes |= types;
@@ -1302,8 +1375,11 @@
if ((typesReady & WindowInsets.Type.ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
mHost.getInputMethodManager(), null /* icProto */);
+ if (animationType == ANIMATION_TYPE_HIDE) {
+ ImeTracker.forLatency().onHidden(statsToken, ActivityThread::currentApplication);
+ }
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING);
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
+ useInsetsAnimationThread);
@@ -1343,7 +1419,8 @@
private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, @InsetsType int types,
SparseArray<InsetsSourceControl> controls, @AnimationType int animationType,
@Nullable ImeTracker.Token statsToken) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS);
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS);
int typesReady = 0;
boolean imeReady = true;
@@ -1446,13 +1523,13 @@
}
final ImeTracker.Token statsToken = runner.getStatsToken();
if (shown) {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_SHOW);
- ImeTracker.get().onShown(statsToken);
+ ImeTracker.forLogging().onShown(statsToken);
} else {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_HIDE);
- ImeTracker.get().onHidden(statsToken);
+ ImeTracker.forLogging().onHidden(statsToken);
}
reportRequestedVisibleTypes();
}
@@ -1478,13 +1555,13 @@
private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
if (invokeCallback) {
- ImeTracker.get().onCancelled(control.getStatsToken(),
- ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
+ ImeTracker.forLogging().onCancelled(control.getStatsToken(),
+ PHASE_CLIENT_ANIMATION_CANCEL);
control.cancel();
} else {
// Succeeds if invokeCallback is false (i.e. when called from notifyFinished).
- ImeTracker.get().onProgress(control.getStatsToken(),
- ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
+ ImeTracker.forLogging().onProgress(control.getStatsToken(),
+ PHASE_CLIENT_ANIMATION_CANCEL);
}
if (DEBUG) {
Log.d(TAG, TextUtils.formatSimple(
@@ -1649,7 +1726,7 @@
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
- mLoggingListener);
+ mLoggingListener, mJankContext);
// We are about to playing the default animation (show/hide). Passing a null frame indicates
// the controlled types should be animated regardless of the frame.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5ac9819..508c6bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25824,6 +25824,10 @@
* @param selected true if the view must be selected, false otherwise
*/
public void setSelected(boolean selected) {
+ setSelected(selected, true);
+ }
+
+ void setSelected(boolean selected, boolean sendAccessibilityEvent) {
//noinspection DoubleNegation
if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) {
mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0);
@@ -25831,11 +25835,13 @@
invalidate(true);
refreshDrawableState();
dispatchSetSelected(selected);
- if (selected) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- } else {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ if (sendAccessibilityEvent) {
+ if (selected) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
}
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0e4ac01..9f5015c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4631,7 +4631,7 @@
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = 0; i < count; i++) {
- children[i].setSelected(selected);
+ children[i].setSelected(selected, false);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 74e521a..2763607 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5764,7 +5764,7 @@
}
case MSG_SHOW_INSETS: {
final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS);
if (mView == null) {
Log.e(TAG,
@@ -5777,7 +5777,7 @@
}
case MSG_HIDE_INSETS: {
final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS);
mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken);
break;
@@ -10324,10 +10324,10 @@
null /* icProto */);
}
if (viewAncestor != null) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
viewAncestor.showInsets(types, fromIme, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
}
}
@@ -10341,10 +10341,10 @@
null /* icProto */);
}
if (viewAncestor != null) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
viewAncestor.hideInsets(types, fromIme, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
}
}
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index c59d83e..037ce87 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -21,6 +21,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import android.annotation.NonNull;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.os.Handler;
import android.os.IBinder;
@@ -246,6 +247,11 @@
}
@Override
+ public Context getRootViewContext() {
+ return mViewRoot != null ? mViewRoot.getView().getContext() : null;
+ }
+
+ @Override
public int dipToPx(int dips) {
if (mViewRoot != null) {
return mViewRoot.dipToPx(dips);
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 83a6c5a..3da3ab9 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -1638,7 +1638,7 @@
}
connection.attachAccessibilityOverlayToWindow(accessibilityWindowId, sc);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error while calling remote attachAccessibilityOverlayToWindow", re);
+ re.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 3b6ec80..a07dedc 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -16,24 +16,36 @@
package android.view.inputmethod;
+import static com.android.internal.inputmethod.InputMethodDebug.softInputDisplayReasonToString;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_ANIMATION;
+import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_HIDDEN;
+import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_SHOWN;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
+import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
import android.util.Log;
+import android.view.InsetsController.AnimationType;
+import android.view.SurfaceControl;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
+import com.android.internal.util.LatencyTracker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.Arrays;
+import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
@@ -385,15 +397,35 @@
void onHidden(@Nullable Token token);
/**
- * Get the singleton instance of this class.
+ * Get the singleton request tracker instance.
*
- * @return the singleton instance of this class
+ * @return the singleton request tracker instance
*/
@NonNull
- static ImeTracker get() {
+ static ImeTracker forLogging() {
return LOGGER;
}
+ /**
+ * Get the singleton jank tracker instance.
+ *
+ * @return the singleton jank tracker instance
+ */
+ @NonNull
+ static ImeJankTracker forJank() {
+ return JANK_TRACKER;
+ }
+
+ /**
+ * Get the singleton latency tracker instance.
+ *
+ * @return the singleton latency tracker instance
+ */
+ @NonNull
+ static ImeLatencyTracker forLatency() {
+ return LATENCY_TRACKER;
+ }
+
/** The singleton IME tracker instance. */
@NonNull
ImeTracker LOGGER = new ImeTracker() {
@@ -489,6 +521,12 @@
}
};
+ /** The singleton IME tracker instance for instrumenting jank metrics. */
+ ImeJankTracker JANK_TRACKER = new ImeJankTracker();
+
+ /** The singleton IME tracker instance for instrumenting latency metrics. */
+ ImeLatencyTracker LATENCY_TRACKER = new ImeLatencyTracker();
+
/** A token that tracks the progress of an IME request. */
class Token implements Parcelable {
@@ -592,4 +630,153 @@
}
}
}
+
+ /**
+ * Context related to {@link InteractionJankMonitor}.
+ */
+ interface InputMethodJankContext {
+ /**
+ * @return a context associated with a display
+ */
+ Context getDisplayContext();
+
+ /**
+ * @return a SurfaceControl is going to be monitored
+ */
+ SurfaceControl getTargetSurfaceControl();
+
+ /**
+ * @return the package name of the host
+ */
+ String getHostPackageName();
+ }
+
+ /**
+ * Context related to {@link LatencyTracker}.
+ */
+ interface InputMethodLatencyContext {
+ /**
+ * @return a context associated with current application
+ */
+ Context getAppContext();
+ }
+
+ /**
+ * A tracker instance which is in charge of communicating with {@link InteractionJankMonitor}.
+ */
+ final class ImeJankTracker {
+
+ private ImeJankTracker() {
+ }
+
+ /**
+ * Called when the animation, which is going to be monitored, starts.
+ *
+ * @param jankContext context which is needed by {@link InteractionJankMonitor}
+ * @param animType {@link AnimationType}
+ * @param useSeparatedThread {@code true} if the animation is handled by the app,
+ * {@code false} if the animation will be scheduled on the
+ * {@link android.view.InsetsAnimationThread}
+ */
+ public void onRequestAnimation(@NonNull InputMethodJankContext jankContext,
+ @AnimationType int animType, boolean useSeparatedThread) {
+ if (jankContext.getDisplayContext() == null
+ || jankContext.getTargetSurfaceControl() == null) {
+ return;
+ }
+ final Configuration.Builder builder = Configuration.Builder.withSurface(
+ CUJ_IME_INSETS_ANIMATION,
+ jankContext.getDisplayContext(),
+ jankContext.getTargetSurfaceControl())
+ .setTag(String.format(Locale.US, "%d@%d@%s", animType,
+ useSeparatedThread ? 0 : 1, jankContext.getHostPackageName()));
+ InteractionJankMonitor.getInstance().begin(builder);
+ }
+
+ /**
+ * Called when the animation, which is going to be monitored, cancels.
+ */
+ public void onCancelAnimation() {
+ InteractionJankMonitor.getInstance().cancel(CUJ_IME_INSETS_ANIMATION);
+ }
+
+ /**
+ * Called when the animation, which is going to be monitored, ends.
+ */
+ public void onFinishAnimation() {
+ InteractionJankMonitor.getInstance().end(CUJ_IME_INSETS_ANIMATION);
+ }
+ }
+
+ /**
+ * A tracker instance which is in charge of communicating with {@link LatencyTracker}.
+ */
+ final class ImeLatencyTracker {
+
+ private ImeLatencyTracker() {
+ }
+
+ private boolean shouldMonitorLatency(@SoftInputShowHideReason int reason) {
+ return reason == SoftInputShowHideReason.SHOW_SOFT_INPUT
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT
+ || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API
+ || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME;
+ }
+
+ public void onRequestShow(@Nullable Token token, @Origin int origin,
+ @SoftInputShowHideReason int reason,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ if (!shouldMonitorLatency(reason)) return;
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionStart(
+ ACTION_REQUEST_IME_SHOWN,
+ softInputDisplayReasonToString(reason));
+ }
+
+ public void onRequestHide(@Nullable Token token, @Origin int origin,
+ @SoftInputShowHideReason int reason,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ if (!shouldMonitorLatency(reason)) return;
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionStart(
+ ACTION_REQUEST_IME_HIDDEN,
+ softInputDisplayReasonToString(reason));
+ }
+
+ public void onShowFailed(@Nullable Token token, @Phase int phase,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ onShowCancelled(token, phase, latencyContext);
+ }
+
+ public void onHideFailed(@Nullable Token token, @Phase int phase,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ onHideCancelled(token, phase, latencyContext);
+ }
+
+ public void onShowCancelled(@Nullable Token token, @Phase int phase,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionCancel(ACTION_REQUEST_IME_SHOWN);
+ }
+
+ public void onHideCancelled(@Nullable Token token, @Phase int phase,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionCancel(ACTION_REQUEST_IME_HIDDEN);
+ }
+
+ public void onShown(@Nullable Token token,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionEnd(ACTION_REQUEST_IME_SHOWN);
+ }
+
+ public void onHidden(@Nullable Token token,
+ @NonNull InputMethodLatencyContext latencyContext) {
+ LatencyTracker.getInstance(latencyContext.getAppContext())
+ .onActionEnd(ACTION_REQUEST_IME_HIDDEN);
+ }
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 99bd02d..642182b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2045,10 +2045,11 @@
private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken, int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
if (statsToken == null) {
- statsToken = ImeTracker.get().onRequestShow(null /* component */,
+ statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
}
-
+ ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
+ reason, ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
null /* icProto */);
// Re-dispatch if there is a context mismatch.
@@ -2060,12 +2061,15 @@
checkFocus();
synchronized (mH) {
if (!hasServedByInputMethodLocked(view)) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLatency().onShowFailed(
+ statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
+ ActivityThread::currentApplication);
Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
// Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
// TODO(b/229426865): call WindowInsetsController#show instead.
@@ -2095,20 +2099,20 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
synchronized (mH) {
- final ImeTracker.Token statsToken = ImeTracker.get().onRequestShow(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
+ final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
+ null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
SoftInputShowHideReason.SHOW_SOFT_INPUT);
Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
+ " removed soon. If you are using androidx.appcompat.widget.SearchView,"
+ " please update to version 26.0 or newer version.");
if (mCurRootView == null || mCurRootView.getView() == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
// Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
// TODO(b/229426865): call WindowInsetsController#show instead.
@@ -2186,20 +2190,24 @@
private boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
- final ImeTracker.Token statsToken = ImeTracker.get().onRequestHide(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
-
+ final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
+ null /* component */, Process.myUid(),
+ ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
+ ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ reason, ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
this, null /* icProto */);
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
if (servedView == null || servedView.getWindowToken() != windowToken) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLatency().onHideFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
flags, resultReceiver, reason);
@@ -2835,18 +2843,22 @@
@UnsupportedAppUsage
void closeCurrentInput() {
- final ImeTracker.Token statsToken = ImeTracker.get().onRequestHide(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
+ null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
SoftInputShowHideReason.HIDE_SOFT_INPUT);
+ ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT, ActivityThread::currentApplication);
synchronized (mH) {
if (mCurRootView == null || mCurRootView.getView() == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLatency().onHideFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
Log.w(TAG, "No current root view, ignoring closeCurrentInput()");
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
IInputMethodManagerGlobalInvoker.hideSoftInput(
mClient,
@@ -2905,11 +2917,13 @@
synchronized (mH) {
final View servedView = getServedViewLocked();
if (servedView == null || servedView.getWindowToken() != windowToken) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
showSoftInput(servedView, statsToken, 0 /* flags */, null /* resultReceiver */,
SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
@@ -2927,21 +2941,25 @@
*/
public void notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
if (statsToken == null) {
- statsToken = ImeTracker.get().onRequestHide(null /* component */,
+ statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
}
-
+ ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+ ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
null /* icProto */);
synchronized (mH) {
if (!isImeSessionAvailableLocked() || mCurRootView == null
|| mCurRootView.getWindowToken() != windowToken) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLatency().onHideFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
0 /* flags */, null /* resultReceiver */,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b33afa5..95a42aa 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -76,6 +76,7 @@
import android.text.method.KeyListener;
import android.text.method.MetaKeyKeyListener;
import android.text.method.MovementMethod;
+import android.text.method.OffsetMapping;
import android.text.method.WordIterator;
import android.text.style.EasyEditSpan;
import android.text.style.SuggestionRangeSpan;
@@ -571,7 +572,7 @@
mTextView.getContext().getResources().getDisplayMetrics());
final Layout layout = mTextView.getLayout();
- final int line = layout.getLineForOffset(mTextView.getSelectionStart());
+ final int line = layout.getLineForOffset(mTextView.getSelectionStartTransformed());
final int sourceHeight = layout.getLineBottom(line, /* includeLineSpacing= */ false)
- layout.getLineTop(line);
final int height = (int)(sourceHeight * zoom);
@@ -1279,12 +1280,16 @@
* Get the minimum range of paragraphs that contains startOffset and endOffset.
*/
private long getParagraphsRange(int startOffset, int endOffset) {
+ final int startOffsetTransformed = mTextView.originalToTransformed(startOffset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int endOffsetTransformed = mTextView.originalToTransformed(endOffset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
final Layout layout = mTextView.getLayout();
if (layout == null) {
return TextUtils.packRangeInLong(-1, -1);
}
- final CharSequence text = mTextView.getText();
- int minLine = layout.getLineForOffset(startOffset);
+ final CharSequence text = layout.getText();
+ int minLine = layout.getLineForOffset(startOffsetTransformed);
// Search paragraph start.
while (minLine > 0) {
final int prevLineEndOffset = layout.getLineEnd(minLine - 1);
@@ -1293,7 +1298,7 @@
}
minLine--;
}
- int maxLine = layout.getLineForOffset(endOffset);
+ int maxLine = layout.getLineForOffset(endOffsetTransformed);
// Search paragraph end.
while (maxLine < layout.getLineCount() - 1) {
final int lineEndOffset = layout.getLineEnd(maxLine);
@@ -1302,7 +1307,11 @@
}
maxLine++;
}
- return TextUtils.packRangeInLong(layout.getLineStart(minLine), layout.getLineEnd(maxLine));
+ final int paragraphStart = mTextView.transformedToOriginal(layout.getLineStart(minLine),
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int paragraphEnd = mTextView.transformedToOriginal(layout.getLineEnd(maxLine),
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ return TextUtils.packRangeInLong(paragraphStart, paragraphEnd);
}
void onLocaleChanged() {
@@ -1339,8 +1348,16 @@
private int getNextCursorOffset(int offset, boolean findAfterGivenOffset) {
final Layout layout = mTextView.getLayout();
if (layout == null) return offset;
- return findAfterGivenOffset == layout.isRtlCharAt(offset)
- ? layout.getOffsetToLeftOf(offset) : layout.getOffsetToRightOf(offset);
+ final int offsetTransformed =
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int nextCursor;
+ if (findAfterGivenOffset == layout.isRtlCharAt(offsetTransformed)) {
+ nextCursor = layout.getOffsetToLeftOf(offsetTransformed);
+ } else {
+ nextCursor = layout.getOffsetToRightOf(offsetTransformed);
+ }
+
+ return mTextView.transformedToOriginal(nextCursor, OffsetMapping.MAP_STRATEGY_CURSOR);
}
private long getCharClusterRange(int offset) {
@@ -1396,9 +1413,11 @@
Layout layout = mTextView.getLayout();
if (layout == null) return false;
- final int line = layout.getLineForOffset(offset);
+ final int offsetTransformed =
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int line = layout.getLineForOffset(offsetTransformed);
final int lineBottom = layout.getLineBottom(line);
- final int primaryHorizontal = (int) layout.getPrimaryHorizontal(offset);
+ final int primaryHorizontal = (int) layout.getPrimaryHorizontal(offsetTransformed);
return mTextView.isPositionVisible(
primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
lineBottom + mTextView.viewportToContentVerticalOffset());
@@ -2300,8 +2319,12 @@
*/
void invalidateTextDisplayList(Layout layout, int start, int end) {
if (mTextRenderNodes != null && layout instanceof DynamicLayout) {
- final int firstLine = layout.getLineForOffset(start);
- final int lastLine = layout.getLineForOffset(end);
+ final int startTransformed =
+ mTextView.originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CHARACTER);
+ final int endTransformed =
+ mTextView.originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CHARACTER);
+ final int firstLine = layout.getLineForOffset(startTransformed);
+ final int lastLine = layout.getLineForOffset(endTransformed);
DynamicLayout dynamicLayout = (DynamicLayout) layout;
int[] blockEndLines = dynamicLayout.getBlockEndLines();
@@ -2344,12 +2367,14 @@
final Layout layout = mTextView.getLayout();
final int offset = mTextView.getSelectionStart();
- final int line = layout.getLineForOffset(offset);
+ final int transformedOffset = mTextView.originalToTransformed(offset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int line = layout.getLineForOffset(transformedOffset);
final int top = layout.getLineTop(line);
final int bottom = layout.getLineBottom(line, /* includeLineSpacing= */ false);
final boolean clamped = layout.shouldClampCursor(line);
- updateCursorPosition(top, bottom, layout.getPrimaryHorizontal(offset, clamped));
+ updateCursorPosition(top, bottom, layout.getPrimaryHorizontal(transformedOffset, clamped));
}
void refreshTextActionMode() {
@@ -3628,10 +3653,14 @@
measureContent();
final int width = mContentView.getMeasuredWidth();
final int offset = getTextOffset();
- mPositionX = (int) (mTextView.getLayout().getPrimaryHorizontal(offset) - width / 2.0f);
+ final int transformedOffset = mTextView.originalToTransformed(offset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ final Layout layout = mTextView.getLayout();
+
+ mPositionX = (int) (layout.getPrimaryHorizontal(transformedOffset) - width / 2.0f);
mPositionX += mTextView.viewportToContentHorizontalOffset();
- final int line = mTextView.getLayout().getLineForOffset(offset);
+ final int line = layout.getLineForOffset(transformedOffset);
mPositionY = getVerticalLocalPosition(line);
mPositionY += mTextView.viewportToContentVerticalOffset();
}
@@ -4564,19 +4593,20 @@
super.onGetContentRect(mode, view, outRect);
return;
}
- if (mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
+ final int selectionStart = mTextView.getSelectionStartTransformed();
+ final int selectionEnd = mTextView.getSelectionEndTransformed();
+ final Layout layout = mTextView.getLayout();
+ if (selectionStart != selectionEnd) {
// We have a selection.
mSelectionPath.reset();
- mTextView.getLayout().getSelectionPath(
- mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath);
+ layout.getSelectionPath(selectionStart, selectionEnd, mSelectionPath);
mSelectionPath.computeBounds(mSelectionBounds, true);
mSelectionBounds.bottom += mHandleHeight;
} else {
// We have a cursor.
- Layout layout = mTextView.getLayout();
- int line = layout.getLineForOffset(mTextView.getSelectionStart());
- float primaryHorizontal = clampHorizontalPosition(null,
- layout.getPrimaryHorizontal(mTextView.getSelectionStart()));
+ int line = layout.getLineForOffset(selectionStart);
+ float primaryHorizontal =
+ clampHorizontalPosition(null, layout.getPrimaryHorizontal(selectionEnd));
mSelectionBounds.set(
primaryHorizontal,
layout.getLineTop(line),
@@ -4679,8 +4709,9 @@
mTextView.viewportToContentHorizontalOffset();
final float viewportToContentVerticalOffset =
mTextView.viewportToContentVerticalOffset();
-
- if (includeCharacterBounds) {
+ final boolean isTextTransformed = (mTextView.getTransformationMethod() != null
+ && mTextView.getTransformed() instanceof OffsetMapping);
+ if (includeCharacterBounds && !isTextTransformed) {
final CharSequence text = mTextView.getText();
if (text instanceof Spannable) {
final Spannable sp = (Spannable) text;
@@ -4708,10 +4739,12 @@
if (includeInsertionMarker) {
// Treat selectionStart as the insertion point.
if (0 <= selectionStart) {
- final int offset = selectionStart;
- final int line = layout.getLineForOffset(offset);
- final float insertionMarkerX = layout.getPrimaryHorizontal(offset)
- + viewportToContentHorizontalOffset;
+ final int offsetTransformed = mTextView.originalToTransformed(
+ selectionStart, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int line = layout.getLineForOffset(offsetTransformed);
+ final float insertionMarkerX =
+ layout.getPrimaryHorizontal(offsetTransformed)
+ + viewportToContentHorizontalOffset;
final float insertionMarkerTop = layout.getLineTop(line)
+ viewportToContentVerticalOffset;
final float insertionMarkerBaseline = layout.getLineBaseline(line)
@@ -4730,7 +4763,7 @@
if (!isTopVisible || !isBottomVisible) {
insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
}
- if (layout.isRtlCharAt(offset)) {
+ if (layout.isRtlCharAt(offsetTransformed)) {
insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
}
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
@@ -5107,12 +5140,28 @@
protected abstract int getMagnifierHandleTrigger();
protected boolean isAtRtlRun(@NonNull Layout layout, int offset) {
- return layout.isRtlCharAt(offset);
+ final int transformedOffset =
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
+ return layout.isRtlCharAt(transformedOffset);
}
@VisibleForTesting
public float getHorizontal(@NonNull Layout layout, int offset) {
- return layout.getPrimaryHorizontal(offset);
+ final int transformedOffset =
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
+ return layout.getPrimaryHorizontal(transformedOffset);
+ }
+
+ /**
+ * Return the line number for a given offset.
+ * @param layout the {@link Layout} to query.
+ * @param offset the index of the character to query.
+ * @return the index of the line the given offset belongs to.
+ */
+ public int getLineForOffset(@NonNull Layout layout, int offset) {
+ final int transformedOffset =
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
+ return layout.getLineForOffset(transformedOffset);
}
protected int getOffsetAtCoordinate(@NonNull Layout layout, int line, float x) {
@@ -5129,13 +5178,12 @@
protected void positionAtCursorOffset(int offset, boolean forceUpdatePosition,
boolean fromTouchScreen) {
// A HandleView relies on the layout, which may be nulled by external methods
- Layout layout = mTextView.getLayout();
+ final Layout layout = mTextView.getLayout();
if (layout == null) {
// Will update controllers' state, hiding them and stopping selection mode if needed
prepareCursorControllers();
return;
}
- layout = mTextView.getLayout();
boolean offsetChanged = offset != mPreviousOffset;
if (offsetChanged || forceUpdatePosition) {
@@ -5146,7 +5194,7 @@
}
addPositionToTouchUpFilter(offset);
}
- final int line = layout.getLineForOffset(offset);
+ final int line = getLineForOffset(layout, offset);
mPrevLine = line;
mPositionX = getCursorHorizontalPosition(layout, offset) - mHotspotX
@@ -5246,7 +5294,7 @@
private boolean tooLargeTextForMagnifier() {
if (mNewMagnifierEnabled) {
Layout layout = mTextView.getLayout();
- final int line = layout.getLineForOffset(getCurrentCursorOffset());
+ final int line = getLineForOffset(layout, getCurrentCursorOffset());
return layout.getLineBottom(line, /* includeLineSpacing= */ false)
- layout.getLineTop(line) >= mMaxLineHeightForMagnifier;
}
@@ -5337,11 +5385,11 @@
}
final Layout layout = mTextView.getLayout();
- final int lineNumber = layout.getLineForOffset(offset);
+ final int lineNumber = getLineForOffset(layout, offset);
// Compute whether the selection handles are currently on the same line, and,
// in this particular case, whether the selected text is right to left.
final boolean sameLineSelection = otherHandleOffset != -1
- && lineNumber == layout.getLineForOffset(otherHandleOffset);
+ && lineNumber == getLineForOffset(layout, offset);
final boolean rtl = sameLineSelection
&& (offset < otherHandleOffset)
!= (getHorizontal(mTextView.getLayout(), offset)
@@ -5468,7 +5516,7 @@
if (mNewMagnifierEnabled) {
// Calculates the line bounds as the content source bounds to the magnifier.
Layout layout = mTextView.getLayout();
- int line = layout.getLineForOffset(getCurrentCursorOffset());
+ int line = getLineForOffset(layout, getCurrentCursorOffset());
int lineLeft = (int) layout.getLineLeft(line);
lineLeft += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
int lineRight = (int) layout.getLineRight(line);
@@ -5838,7 +5886,7 @@
private MotionEvent transformEventForTouchThrough(MotionEvent ev) {
final Layout layout = mTextView.getLayout();
- final int line = layout.getLineForOffset(getCurrentCursorOffset());
+ final int line = getLineForOffset(layout, getCurrentCursorOffset());
final int textHeight = layout.getLineBottom(line, /* includeLineSpacing= */ false)
- layout.getLineTop(line);
// Transforms the touch events to screen coordinates.
@@ -6050,7 +6098,7 @@
|| !isStartHandle() && initialOffset <= anotherHandleOffset) {
// Handles have crossed, bound it to the first selected line and
// adjust by word / char as normal.
- currLine = layout.getLineForOffset(anotherHandleOffset);
+ currLine = getLineForOffset(layout, anotherHandleOffset);
initialOffset = getOffsetAtCoordinate(layout, currLine, x);
}
@@ -6065,7 +6113,8 @@
final int currentOffset = getCurrentCursorOffset();
final boolean rtlAtCurrentOffset = isAtRtlRun(layout, currentOffset);
final boolean atRtl = isAtRtlRun(layout, offset);
- final boolean isLvlBoundary = layout.isLevelBoundary(offset);
+ final boolean isLvlBoundary = layout.isLevelBoundary(
+ mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR));
// We can't determine if the user is expanding or shrinking the selection if they're
// on a bi-di boundary, so until they've moved past the boundary we'll just place
@@ -6077,7 +6126,9 @@
mTouchWordDelta = 0.0f;
positionAndAdjustForCrossingHandles(offset, fromTouchScreen);
return;
- } else if (mLanguageDirectionChanged && !isLvlBoundary) {
+ }
+
+ if (mLanguageDirectionChanged) {
// We've just moved past the boundary so update the position. After this we can
// figure out if the user is expanding or shrinking to go by word or character.
positionAndAdjustForCrossingHandles(offset, fromTouchScreen);
@@ -6129,7 +6180,7 @@
// Sometimes words can be broken across lines (Chinese, hyphenation).
// We still snap to the word boundary but we only use the letters on the
// current line to determine if the user is far enough into the word to snap.
- if (layout.getLineForOffset(wordBoundary) != currLine) {
+ if (getLineForOffset(layout, wordBoundary) != currLine) {
wordBoundary = isStartHandle()
? layout.getLineStart(currLine) : layout.getLineEnd(currLine);
}
@@ -6253,12 +6304,15 @@
final int currentOffset = getCurrentCursorOffset();
final int offsetToGetRunRange = isStartHandle()
? currentOffset : Math.max(currentOffset - 1, 0);
- final long range = layout.getRunRange(offsetToGetRunRange);
+ final long range = layout.getRunRange(mTextView.originalToTransformed(
+ offsetToGetRunRange, OffsetMapping.MAP_STRATEGY_CURSOR));
if (isStartHandle()) {
offset = TextUtils.unpackRangeStartFromLong(range);
} else {
offset = TextUtils.unpackRangeEndFromLong(range);
}
+ offset = mTextView.transformedToOriginal(offset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
positionAtCursorOffset(offset, false, fromTouchScreen);
return;
}
@@ -6285,7 +6339,10 @@
@Override
protected boolean isAtRtlRun(@NonNull Layout layout, int offset) {
- final int offsetToCheck = isStartHandle() ? offset : Math.max(offset - 1, 0);
+ final int transformedOffset =
+ mTextView.transformedToOriginal(offset, OffsetMapping.MAP_STRATEGY_CHARACTER);
+ final int offsetToCheck = isStartHandle() ? transformedOffset
+ : Math.max(transformedOffset - 1, 0);
return layout.isRtlCharAt(offsetToCheck);
}
@@ -6295,12 +6352,17 @@
}
private float getHorizontal(@NonNull Layout layout, int offset, boolean startHandle) {
- final int line = layout.getLineForOffset(offset);
- final int offsetToCheck = startHandle ? offset : Math.max(offset - 1, 0);
+ final int offsetTransformed = mTextView.originalToTransformed(offset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int line = layout.getLineForOffset(offsetTransformed);
+ final int offsetToCheck =
+ startHandle ? offsetTransformed : Math.max(offsetTransformed - 1, 0);
final boolean isRtlChar = layout.isRtlCharAt(offsetToCheck);
final boolean isRtlParagraph = layout.getParagraphDirection(line) == -1;
- return (isRtlChar == isRtlParagraph)
- ? layout.getPrimaryHorizontal(offset) : layout.getSecondaryHorizontal(offset);
+ if (isRtlChar != isRtlParagraph) {
+ return layout.getSecondaryHorizontal(offsetTransformed);
+ }
+ return layout.getPrimaryHorizontal(offsetTransformed);
}
@Override
@@ -6308,23 +6370,27 @@
final float localX = mTextView.convertToLocalHorizontalCoordinate(x);
final int primaryOffset = layout.getOffsetForHorizontal(line, localX, true);
if (!layout.isLevelBoundary(primaryOffset)) {
- return primaryOffset;
+ return mTextView.transformedToOriginal(primaryOffset,
+ OffsetMapping.MAP_STRATEGY_CURSOR);
}
final int secondaryOffset = layout.getOffsetForHorizontal(line, localX, false);
- final int currentOffset = getCurrentCursorOffset();
+ final int currentOffset = mTextView.originalToTransformed(getCurrentCursorOffset(),
+ OffsetMapping.MAP_STRATEGY_CURSOR);
final int primaryDiff = Math.abs(primaryOffset - currentOffset);
final int secondaryDiff = Math.abs(secondaryOffset - currentOffset);
+ final int offset;
if (primaryDiff < secondaryDiff) {
- return primaryOffset;
+ offset = primaryOffset;
} else if (primaryDiff > secondaryDiff) {
- return secondaryOffset;
+ offset = secondaryOffset;
} else {
final int offsetToCheck = isStartHandle()
? currentOffset : Math.max(currentOffset - 1, 0);
final boolean isRtlChar = layout.isRtlCharAt(offsetToCheck);
final boolean isRtlParagraph = layout.getParagraphDirection(line) == -1;
- return isRtlChar == isRtlParagraph ? primaryOffset : secondaryOffset;
+ offset = (isRtlChar == isRtlParagraph) ? primaryOffset : secondaryOffset;
}
+ return mTextView.transformedToOriginal(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
}
@MagnifierHandleTrigger
@@ -7165,7 +7231,10 @@
int end = Math.min(length, mEnd);
mPath.reset();
- layout.getSelectionPath(start, end, mPath);
+ layout.getSelectionPath(
+ mTextView.originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CHARACTER),
+ mTextView.originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CHARACTER),
+ mPath);
return true;
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 075aa6c..c1800cf 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,6 +33,7 @@
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
+import android.text.method.OffsetMapping;
import android.text.util.Linkify;
import android.util.Log;
import android.view.ActionMode;
@@ -329,8 +330,6 @@
private void startSelectionActionModeWithSmartSelectAnimation(
@Nullable SelectionResult result) {
- final Layout layout = mTextView.getLayout();
-
final Runnable onAnimationEndCallback = () -> {
final SelectionResult startSelectionResult;
if (result != null && result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
@@ -352,7 +351,7 @@
}
final List<SmartSelectSprite.RectangleWithTextSelectionLayout> selectionRectangles =
- convertSelectionToRectangles(layout, result.mStart, result.mEnd);
+ convertSelectionToRectangles(mTextView, result.mStart, result.mEnd);
final PointF touchPoint = new PointF(
mEditor.getLastUpPositionX(),
@@ -369,7 +368,7 @@
}
private List<SmartSelectSprite.RectangleWithTextSelectionLayout> convertSelectionToRectangles(
- final Layout layout, final int start, final int end) {
+ final TextView textView, final int start, final int end) {
final List<SmartSelectSprite.RectangleWithTextSelectionLayout> result = new ArrayList<>();
final Layout.SelectionRectangleConsumer consumer =
@@ -381,7 +380,11 @@
textSelectionLayout)
);
- layout.getSelection(start, end, consumer);
+ final int startTransformed =
+ textView.originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int endTransformed =
+ textView.originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CURSOR);
+ textView.getLayout().getSelection(startTransformed, endTransformed, consumer);
result.sort(Comparator.comparing(
SmartSelectSprite.RectangleWithTextSelectionLayout::getRectangle,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d6c2d30..6ff808e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -135,6 +135,7 @@
import android.text.method.LinkMovementMethod;
import android.text.method.MetaKeyKeyListener;
import android.text.method.MovementMethod;
+import android.text.method.OffsetMapping;
import android.text.method.PasswordTransformationMethod;
import android.text.method.SingleLineTransformationMethod;
import android.text.method.TextKeyListener;
@@ -456,6 +457,14 @@
private static final int CHANGE_WATCHER_PRIORITY = 100;
+ /**
+ * The span priority of the {@link TransformationMethod} that is set on the text. It must be
+ * higher than the {@link DynamicLayout}'s {@link TextWatcher}, so that the transformed text is
+ * updated before {@link DynamicLayout#reflow(CharSequence, int, int, int)} being triggered
+ * by {@link TextWatcher#onTextChanged(CharSequence, int, int, int)}.
+ */
+ private static final int TRANSFORMATION_SPAN_PRIORITY = 200;
+
// New state used to change background based on whether this TextView is multiline.
private static final int[] MULTILINE_STATE_SET = { R.attr.state_multiline };
@@ -7009,7 +7018,8 @@
final int textLength = text.length();
- if (text instanceof Spannable && !mAllowTransformationLengthChange) {
+ if (text instanceof Spannable && (!mAllowTransformationLengthChange
+ || text instanceof OffsetMapping)) {
Spannable sp = (Spannable) text;
// Remove any ChangeWatchers that might have come from other TextViews.
@@ -7027,7 +7037,8 @@
if (mEditor != null) mEditor.addSpanWatchers(sp);
if (mTransformation != null) {
- sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE
+ | (TRANSFORMATION_SPAN_PRIORITY << Spanned.SPAN_PRIORITY_SHIFT));
}
if (mMovement != null) {
@@ -8226,6 +8237,8 @@
if (mLayout == null) {
invalidate();
} else {
+ start = originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CURSOR);
+ end = originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CURSOR);
int lineStart = mLayout.getLineForOffset(start);
int top = mLayout.getLineTop(lineStart);
@@ -8715,8 +8728,8 @@
Path highlight = null;
Paint highlightPaint = mHighlightPaint;
- final int selStart = getSelectionStart();
- final int selEnd = getSelectionEnd();
+ final int selStart = getSelectionStartTransformed();
+ final int selEnd = getSelectionEndTransformed();
if (mMovement != null && (isFocused() || isPressed()) && selStart >= 0) {
if (selStart == selEnd) {
if (mEditor != null && mEditor.shouldRenderCursor()) {
@@ -8937,13 +8950,13 @@
return;
}
- int selEnd = getSelectionEnd();
+ int selEnd = getSelectionEndTransformed();
if (selEnd < 0) {
super.getFocusedRect(r);
return;
}
- int selStart = getSelectionStart();
+ int selStart = getSelectionStartTransformed();
if (selStart < 0 || selStart >= selEnd) {
int line = mLayout.getLineForOffset(selEnd);
r.top = mLayout.getLineTop(line);
@@ -9826,6 +9839,14 @@
return false;
}
+ /**
+ * Return whether the text is transformed and has {@link OffsetMapping}.
+ * @hide
+ */
+ public boolean isOffsetMappingAvailable() {
+ return mTransformation != null && mTransformed instanceof OffsetMapping;
+ }
+
/** @hide */
public boolean previewHandwritingGesture(
@NonNull PreviewableHandwritingGesture gesture,
@@ -9855,6 +9876,9 @@
}
private int performHandwritingSelectGesture(@NonNull SelectGesture gesture, boolean isPreview) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
int[] range = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getSelectionArea()),
gesture.getGranularity());
@@ -9881,6 +9905,9 @@
private int performHandwritingSelectRangeGesture(
@NonNull SelectRangeGesture gesture, boolean isPreview) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
int[] startRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getSelectionStartArea()),
gesture.getGranularity());
@@ -9905,6 +9932,9 @@
}
private int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture, boolean isPreview) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
int[] range = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getDeletionArea()),
gesture.getGranularity());
@@ -9935,6 +9965,9 @@
private int performHandwritingDeleteRangeGesture(
@NonNull DeleteRangeGesture gesture, boolean isPreview) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
int[] startRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getDeletionStartArea()),
gesture.getGranularity());
@@ -10015,6 +10048,9 @@
/** @hide */
public int performHandwritingInsertGesture(@NonNull InsertGesture gesture) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
PointF point = convertFromScreenToContentCoordinates(gesture.getInsertionPoint());
int line = getLineForHandwritingGesture(point);
if (line == -1) {
@@ -10030,6 +10066,9 @@
/** @hide */
public int performHandwritingRemoveSpaceGesture(@NonNull RemoveSpaceGesture gesture) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
PointF startPoint = convertFromScreenToContentCoordinates(gesture.getStartPoint());
PointF endPoint = convertFromScreenToContentCoordinates(gesture.getEndPoint());
@@ -10088,6 +10127,9 @@
/** @hide */
public int performHandwritingJoinOrSplitGesture(@NonNull JoinOrSplitGesture gesture) {
+ if (isOffsetMappingAvailable()) {
+ return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+ }
PointF point = convertFromScreenToContentCoordinates(gesture.getJoinOrSplitPoint());
int line = getLineForHandwritingGesture(point);
@@ -11179,13 +11221,15 @@
mDeferScroll = offset;
return false;
}
+ final int offsetTransformed =
+ originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
boolean changed = false;
Layout layout = isShowingHint() ? mHintLayout : mLayout;
if (layout == null) return changed;
- int line = layout.getLineForOffset(offset);
+ int line = layout.getLineForOffset(offsetTransformed);
int grav;
@@ -11220,7 +11264,7 @@
// right where it is most likely to be annoying.
final boolean clamped = grav > 0;
// FIXME: Is it okay to truncate this, or should we round?
- final int x = (int) layout.getPrimaryHorizontal(offset, clamped);
+ final int x = (int) layout.getPrimaryHorizontal(offsetTransformed, clamped);
final int top = layout.getLineTop(line);
final int bottom = layout.getLineTop(line + 1);
@@ -11384,8 +11428,8 @@
if (!(mText instanceof Spannable)) {
return false;
}
- int start = getSelectionStart();
- int end = getSelectionEnd();
+ int start = getSelectionStartTransformed();
+ int end = getSelectionEndTransformed();
if (start != end) {
return false;
}
@@ -11428,7 +11472,8 @@
}
if (newStart != start) {
- Selection.setSelection(mSpannable, newStart);
+ Selection.setSelection(mSpannable,
+ transformedToOriginal(newStart, OffsetMapping.MAP_STRATEGY_CURSOR));
return true;
}
@@ -11537,6 +11582,35 @@
}
/**
+ * Calculates the rectangles which should be highlighted to indicate a selection between start
+ * and end and feeds them into the given {@link Layout.SelectionRectangleConsumer}.
+ *
+ * @param start the starting index of the selection
+ * @param end the ending index of the selection
+ * @param consumer the {@link Layout.SelectionRectangleConsumer} which will receive the
+ * generated rectangles. It will be called every time a rectangle is generated.
+ * @hide
+ */
+ public void getSelection(int start, int end, final Layout.SelectionRectangleConsumer consumer) {
+ final int transformedStart =
+ originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int transformedEnd = originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CURSOR);
+ mLayout.getSelection(transformedStart, transformedEnd, consumer);
+ }
+
+ int getSelectionStartTransformed() {
+ final int start = getSelectionStart();
+ if (start < 0) return start;
+ return originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CURSOR);
+ }
+
+ int getSelectionEndTransformed() {
+ final int end = getSelectionEnd();
+ if (end < 0) return end;
+ return originalToTransformed(end, OffsetMapping.MAP_STRATEGY_CURSOR);
+ }
+
+ /**
* Return true iff there is a selection of nonzero length inside this text view.
*/
public boolean hasSelection() {
@@ -13186,8 +13260,12 @@
}
// Convert lines into character offsets.
- int expandedTopChar = layout.getLineStart(expandedTopLine);
- int expandedBottomChar = layout.getLineEnd(expandedBottomLine);
+ int expandedTopChar = transformedToOriginal(
+ layout.getLineStart(expandedTopLine),
+ OffsetMapping.MAP_STRATEGY_CHARACTER);
+ int expandedBottomChar = transformedToOriginal(
+ layout.getLineEnd(expandedBottomLine),
+ OffsetMapping.MAP_STRATEGY_CHARACTER);
// Take into account selection -- if there is a selection, we need to expand
// the text we are returning to include that selection.
@@ -13230,8 +13308,10 @@
final int[] lineBaselines = new int[bottomLine - topLine + 1];
final int baselineOffset = getBaselineOffset();
for (int i = topLine; i <= bottomLine; i++) {
- lineOffsets[i - topLine] = layout.getLineStart(i);
- lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+ lineOffsets[i - topLine] = transformedToOriginal(layout.getLineStart(i),
+ OffsetMapping.MAP_STRATEGY_CHARACTER);
+ lineBaselines[i - topLine] =
+ layout.getLineBaseline(i) + baselineOffset;
}
structure.setTextLines(lineOffsets, lineBaselines);
}
@@ -13537,6 +13617,11 @@
public void populateCharacterBounds(CursorAnchorInfo.Builder builder,
int startIndex, int endIndex, float viewportToContentHorizontalOffset,
float viewportToContentVerticalOffset) {
+ if (isOffsetMappingAvailable()) {
+ // The text is transformed, and has different length, we don't support
+ // character bounds in this case yet.
+ return;
+ }
final Rect rect = new Rect();
getLocalVisibleRect(rect);
final RectF visibleRect = new RectF(rect);
@@ -13601,8 +13686,8 @@
return null;
}
final CharSequence text = layout.getText();
- if (text == null) {
- // It's impossible that a layout has no text. Check here to avoid NPE.
+ if (text == null || isOffsetMappingAvailable()) {
+ // The text is Null or the text has been transformed. Can't provide TextBoundsInfo.
return null;
}
@@ -14624,10 +14709,40 @@
int getOffsetAtCoordinate(int line, float x) {
x = convertToLocalHorizontalCoordinate(x);
- return getLayout().getOffsetForHorizontal(line, x);
+ final int offset = getLayout().getOffsetForHorizontal(line, x);
+ return transformedToOriginal(offset, OffsetMapping.MAP_STRATEGY_CURSOR);
}
/**
+ * Convenient method to convert an offset on the transformed text to the original text.
+ * @hide
+ */
+ public int transformedToOriginal(int offset, @OffsetMapping.MapStrategy int strategy) {
+ if (getTransformationMethod() == null) {
+ return offset;
+ }
+ if (mTransformed instanceof OffsetMapping) {
+ final OffsetMapping transformedText = (OffsetMapping) mTransformed;
+ return transformedText.transformedToOriginal(offset, strategy);
+ }
+ return offset;
+ }
+
+ /**
+ * Convenient method to convert an offset on the original text to the transformed text.
+ * @hide
+ */
+ public int originalToTransformed(int offset, @OffsetMapping.MapStrategy int strategy) {
+ if (getTransformationMethod() == null) {
+ return offset;
+ }
+ if (mTransformed instanceof OffsetMapping) {
+ final OffsetMapping transformedText = (OffsetMapping) mTransformed;
+ return transformedText.originalToTransformed(offset, strategy);
+ }
+ return offset;
+ }
+ /**
* Handles drag events sent by the system following a call to
* {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int)
* startDragAndDrop()}.
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 970728f..56da8e0 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,6 +3,7 @@
per-file *Chooser* = file:/packages/SystemUI/OWNERS
per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
per-file AbstractMultiProfilePagerAdapter.java = file:/packages/SystemUI/OWNERS
+per-file *EmptyStateProvider.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java b/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java
new file mode 100644
index 0000000..ddd3d2c
--- /dev/null
+++ b/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java
@@ -0,0 +1,107 @@
+/*
+ * 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.config.appcloning;
+
+import android.content.Context;
+import android.provider.DeviceConfig;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Helper class that holds the flags related to the app_cloning namespace in {@link DeviceConfig}.
+ *
+ * @hide
+ */
+public class AppCloningDeviceConfigHelper {
+
+ @GuardedBy("sLock")
+ private static AppCloningDeviceConfigHelper sInstance;
+
+ private static final Object sLock = new Object();
+
+ private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangeListener;
+
+ /**
+ * This flag is defined inside {@link DeviceConfig#NAMESPACE_APP_CLONING}. Please check
+ * {@link #mEnableAppCloningBuildingBlocks} for details.
+ */
+ public static final String ENABLE_APP_CLONING_BUILDING_BLOCKS =
+ "enable_app_cloning_building_blocks";
+
+ /**
+ * Checks whether the support for app-cloning building blocks (like contacts
+ * sharing/intent redirection), which are available starting from the U release, is turned on.
+ * The default value is true to ensure the features are always enabled going forward.
+ *
+ * TODO:(b/253449368) Add information about the app-cloning config and mention that the devices
+ * that do not support app-cloning should use the app-cloning config to disable all app-cloning
+ * features.
+ */
+ private volatile boolean mEnableAppCloningBuildingBlocks = true;
+
+ private AppCloningDeviceConfigHelper() {}
+
+ /**
+ * @hide
+ */
+ public static AppCloningDeviceConfigHelper getInstance(Context context) {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new AppCloningDeviceConfigHelper();
+ sInstance.init(context);
+ }
+ return sInstance;
+ }
+ }
+
+ private void init(Context context) {
+ initializeDeviceConfigChangeListener();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_CLONING,
+ context.getMainExecutor(),
+ mDeviceConfigChangeListener);
+ }
+
+ private void initializeDeviceConfigChangeListener() {
+ mDeviceConfigChangeListener = properties -> {
+ if (!DeviceConfig.NAMESPACE_APP_CLONING.equals(properties.getNamespace())) {
+ return;
+ }
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ return;
+ }
+ if (ENABLE_APP_CLONING_BUILDING_BLOCKS.equals(name)) {
+ updateEnableAppCloningBuildingBlocks();
+ }
+ }
+ };
+ }
+
+ private void updateEnableAppCloningBuildingBlocks() {
+ mEnableAppCloningBuildingBlocks = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_APP_CLONING, ENABLE_APP_CLONING_BUILDING_BLOCKS, true);
+ }
+
+ /**
+ * Fetch the feature flag to check whether the support for the app-cloning building blocks
+ * (like contacts sharing/intent redirection) is enabled on the device.
+ * @hide
+ */
+ public boolean getEnableAppCloningBuildingBlocks() {
+ return mEnableAppCloningBuildingBlocks;
+ }
+}
diff --git a/core/java/com/android/internal/config/appcloning/OWNERS b/core/java/com/android/internal/config/appcloning/OWNERS
new file mode 100644
index 0000000..0645a8c5
--- /dev/null
+++ b/core/java/com/android/internal/config/appcloning/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1207885
+jigarthakkar@google.com
+saumyap@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d9e9a5f..95a47ea 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,11 +16,15 @@
package com.android.internal.jank;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -89,17 +93,19 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.UiThread;
import android.annotation.WorkerThread;
+import android.app.ActivityThread;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -232,6 +238,7 @@
public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
+ public static final int CUJ_IME_INSETS_ANIMATION = 69;
private static final int NO_STATSD_LOGGING = -1;
@@ -309,6 +316,7 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION,
};
private static class InstanceHolder {
@@ -401,7 +409,8 @@
CUJ_RECENTS_SCROLLING,
CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
- CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME
+ CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ CUJ_IME_INSETS_ANIMATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -422,29 +431,37 @@
* @param worker the worker thread for the callbacks
*/
@VisibleForTesting
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
public InteractionJankMonitor(@NonNull HandlerThread worker) {
- // Check permission early.
- Settings.Config.enforceReadPermission(
- DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR);
-
mRunningTrackers = new SparseArray<>();
mTimeoutActions = new SparseArray<>();
mWorker = worker;
mWorker.start();
- mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler());
-
- // Post initialization to the background in case we're running on the main
- // thread.
- mWorker.getThreadHandler().post(
- () -> mPropertiesChangedListener.onPropertiesChanged(
- DeviceConfig.getProperties(
- DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR)));
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR,
- new HandlerExecutor(mWorker.getThreadHandler()),
- mPropertiesChangedListener);
+ mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
mEnabled = DEFAULT_ENABLED;
+
+ final Context context = ActivityThread.currentApplication();
+ if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
+ // Post initialization to the background in case we're running on the main thread.
+ mWorker.getThreadHandler().post(
+ () -> mPropertiesChangedListener.onPropertiesChanged(
+ DeviceConfig.getProperties(
+ DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR)));
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR,
+ new HandlerExecutor(mWorker.getThreadHandler()),
+ mPropertiesChangedListener);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Initialized the InteractionJankMonitor."
+ + " (No READ_DEVICE_CONFIG permission to change configs)"
+ + " enabled=" + mEnabled + ", interval=" + mSamplingInterval
+ + ", missedFrameThreshold=" + mTraceThresholdMissedFrames
+ + ", frameTimeThreshold=" + mTraceThresholdFrameTimeMillis
+ + ", package=" + context.getPackageName());
+ }
+ }
}
/**
@@ -923,6 +940,8 @@
return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
+ case CUJ_IME_INSETS_ANIMATION:
+ return "IME_INSETS_ANIMATION";
}
return "UNKNOWN";
}
@@ -1178,7 +1197,7 @@
*/
@VisibleForTesting
public int getDisplayId() {
- return (mSurfaceOnly ? mContext.getDisplay() : mView.getDisplay()).getDisplayId();
+ return mSurfaceOnly ? mContext.getDisplayId() : mView.getContext().getDisplayId();
}
}
diff --git a/core/java/com/android/internal/power/EnergyConsumerStats.java b/core/java/com/android/internal/power/EnergyConsumerStats.java
index 8cf17cda..e2098dd 100644
--- a/core/java/com/android/internal/power/EnergyConsumerStats.java
+++ b/core/java/com/android/internal/power/EnergyConsumerStats.java
@@ -59,7 +59,8 @@
public static final int POWER_BUCKET_GNSS = 6;
public static final int POWER_BUCKET_MOBILE_RADIO = 7;
public static final int POWER_BUCKET_CAMERA = 8;
- public static final int NUMBER_STANDARD_POWER_BUCKETS = 9; // Buckets above this are custom.
+ public static final int POWER_BUCKET_PHONE = 9;
+ public static final int NUMBER_STANDARD_POWER_BUCKETS = 10; // Buckets above this are custom.
@IntDef(prefix = {"POWER_BUCKET_"}, value = {
POWER_BUCKET_UNKNOWN,
@@ -72,6 +73,7 @@
POWER_BUCKET_GNSS,
POWER_BUCKET_MOBILE_RADIO,
POWER_BUCKET_CAMERA,
+ POWER_BUCKET_PHONE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StandardPowerBucket {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 8fb345b..a704eb3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -337,4 +337,11 @@
* @param leftOrTop indicates where the stage split is.
*/
void enterStageSplitFromRunningApp(boolean leftOrTop);
+
+ /**
+ * Shows the media output switcher dialog.
+ *
+ * @param packageName of the session for which the output switcher is shown.
+ */
+ void showMediaOutputSwitcher(String packageName);
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index afb526a..2d5bb6c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -14,7 +14,10 @@
package com.android.internal.util;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_APP;
+import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
@@ -24,6 +27,8 @@
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
@@ -42,9 +47,12 @@
import static com.android.internal.util.LatencyTracker.ActionProperties.SAMPLE_INTERVAL_SUFFIX;
import static com.android.internal.util.LatencyTracker.ActionProperties.TRACE_THRESHOLD_SUFFIX;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.app.ActivityThread;
import android.content.Context;
import android.os.Build;
import android.os.ConditionVariable;
@@ -187,6 +195,16 @@
*/
public static final int ACTION_SHOW_VOICE_INTERACTION = 19;
+ /**
+ * Time it takes to request IME shown animation.
+ */
+ public static final int ACTION_REQUEST_IME_SHOWN = 20;
+
+ /**
+ * Time it takes to request IME hidden animation.
+ */
+ public static final int ACTION_REQUEST_IME_HIDDEN = 21;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -208,6 +226,8 @@
ACTION_SHOW_SELECTION_TOOLBAR,
ACTION_FOLD_TO_AOD,
ACTION_SHOW_VOICE_INTERACTION,
+ ACTION_REQUEST_IME_SHOWN,
+ ACTION_REQUEST_IME_HIDDEN,
};
/** @hide */
@@ -232,6 +252,8 @@
ACTION_SHOW_SELECTION_TOOLBAR,
ACTION_FOLD_TO_AOD,
ACTION_SHOW_VOICE_INTERACTION,
+ ACTION_REQUEST_IME_SHOWN,
+ ACTION_REQUEST_IME_HIDDEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -259,6 +281,8 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
};
private static LatencyTracker sLatencyTracker;
@@ -284,15 +308,30 @@
return sLatencyTracker;
}
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
@VisibleForTesting
public LatencyTracker() {
mEnabled = DEFAULT_ENABLED;
- // Post initialization to the background in case we're running on the main thread.
- BackgroundThread.getHandler().post(() -> this.updateProperties(
- DeviceConfig.getProperties(DeviceConfig.NAMESPACE_LATENCY_TRACKER)));
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_LATENCY_TRACKER,
- BackgroundThread.getExecutor(), this::updateProperties);
+ final Context context = ActivityThread.currentApplication();
+ if (context != null
+ && context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
+ // Post initialization to the background in case we're running on the main thread.
+ BackgroundThread.getHandler().post(() -> this.updateProperties(
+ DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)));
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
+ BackgroundThread.getExecutor(), this::updateProperties);
+ } else {
+ if (DEBUG) {
+ if (context == null) {
+ Log.d(TAG, "No application for " + ActivityThread.currentActivityThread());
+ } else {
+ Log.d(TAG, "Initialized the LatencyTracker."
+ + " (No READ_DEVICE_CONFIG permission to change configs)"
+ + " enabled=" + mEnabled + ", package=" + context.getPackageName());
+ }
+ }
+ }
}
private void updateProperties(DeviceConfig.Properties properties) {
@@ -368,6 +407,10 @@
return "ACTION_FOLD_TO_AOD";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION:
return "ACTION_SHOW_VOICE_INTERACTION";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN:
+ return "ACTION_REQUEST_IME_SHOWN";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN:
+ return "ACTION_REQUEST_IME_HIDDEN";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 869da1f..058c6ec 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -106,7 +106,9 @@
* Enables or disables rotation lock from the system UI toggle.
*/
public static void setRotationLock(Context context, final boolean enabled) {
- final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
+ final int rotation = areAllRotationsAllowed(context)
+ || useCurrentRotationOnRotationLockChange(context) ? CURRENT_ROTATION
+ : NATURAL_ROTATION;
setRotationLockAtAngle(context, enabled, rotation);
}
@@ -139,6 +141,11 @@
return context.getResources().getBoolean(R.bool.config_allowAllRotations);
}
+ private static boolean useCurrentRotationOnRotationLockChange(Context context) {
+ return context.getResources().getBoolean(
+ R.bool.config_useCurrentRotationOnRotationLockChange);
+ }
+
private static void setRotationLock(final boolean enabled, final int rotation) {
AsyncTask.execute(new Runnable() {
@Override
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 91a5d3a..3c305f6 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -77,11 +77,6 @@
private static final boolean FRP_CREDENTIAL_ENABLED = true;
/**
- * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
- */
- public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
-
- /**
* The interval of the countdown for showing progress of the lockout.
*/
public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
@@ -952,19 +947,6 @@
return type == CREDENTIAL_TYPE_PATTERN;
}
- @Deprecated
- public boolean isLegacyLockPatternEnabled(int userId) {
- // Note: this value should default to {@code true} to avoid any reset that might result.
- // We must use a special key to read this value, since it will by default return the value
- // based on the new logic.
- return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
- }
-
- @Deprecated
- public void setLegacyLockPatternEnabled(int userId) {
- setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
- }
-
/**
* @return Whether the visible pattern is enabled.
*/
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 18d84d5..ab7b0ab 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -543,6 +543,7 @@
DEAD = 15;
NOT_PERCEPTIBLE = 16;
INCLUDE_CAPABILITIES = 17;
+ ALLOW_ACTIVITY_STARTS = 18;
}
repeated Flag flags = 3;
optional string service_name = 4;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c052cca..f74ebc4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5335,6 +5335,14 @@
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
android:protectionLevel="signature|privileged|role" />
+ <!--@SystemApi Allows an application to modify system audio settings that shouldn't be
+ controllable by external apps, such as volume settings or volume behaviors for audio
+ devices, regardless of their connection status.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_AUDIO_SYSTEM_SETTINGS"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to access the uplink and downlink audio of an ongoing
call.
<p>Not for use by third-party applications.</p>
@@ -7032,6 +7040,15 @@
android:protectionLevel="signature|knownSigner"
android:knownCerts="@array/config_healthConnectMigrationKnownSigners" />
+ <!-- @SystemApi Allows an app to query apps in clone profile. The permission is
+ bidirectional in nature, i.e. cloned apps would be able to query apps in root user.
+ The permission is not meant for 3P apps as of now.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.QUERY_CLONED_APPS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 48614ed..8c1b6ed 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Kleurregstelling"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Eenhandmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra donker"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Gehoortoestelle"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
@@ -1942,6 +1943,10 @@
<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="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 3843df9..708b9fd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"የቀለም ማስተካከያ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"የአንድ እጅ ሁነታ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ተጨማሪ ደብዛዛ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"የመስሚያ መሣሪያዎች"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
@@ -1942,6 +1943,10 @@
<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="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 3514ff1..e524fc7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1712,6 +1712,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"تصحيح الألوان"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"وضع \"التصفح بيد واحدة\""</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"زيادة تعتيم الشاشة"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعات الأذن الطبية"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1946,6 +1947,10 @@
<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="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 234534a..5409045 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ৰং শুধৰণী"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এখন হাতেৰে ব্যৱহাৰ কৰাৰ ম’ড"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"এক্সট্ৰা ডিম"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"শুনাৰ ডিভাইচ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
@@ -1942,6 +1943,10 @@
<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="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 f35da2d..efa6c67 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Rəng korreksiyası"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Birəlli rejim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə tündləşmə"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eşitmə cihazları"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
@@ -1942,6 +1943,10 @@
<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="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 d849bb0..0677369 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Korekcija boja"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjeno"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 970fac3..07cdb89 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Карэкцыя колераў"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Рэжым кіравання адной рукой"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дадатковае памяншэнне яркасці"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слыхавыя апараты"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Клавішы гучнасці ўтрымліваліся націснутымі. Уключана служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Клавішы гучнасці ўтрымліваліся націснутымі. Служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" выключана."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
@@ -1944,6 +1945,10 @@
<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="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 c37ed33..4139e95 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Корекция на цветове"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Работа с една ръка"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Доп. затъмн."</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухови апарати"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е изключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
@@ -1942,6 +1943,10 @@
<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="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 ec1ef28..09e592c 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"রঙ সংশোধন করা"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এক হাতে ব্যবহার করার মোড"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম আলো"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"হিয়ারিং ডিভাইস"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করা হয়েছে।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> বন্ধ করা হয়েছে।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
@@ -1942,6 +1943,10 @@
<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="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 db572e0..4bc3399 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Ispravka boja"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjeno"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 b5e2c76..b863fb5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correcció de color"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode d\'una mà"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuació extra"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audiòfons"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 7fe373f..10b92c8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Korekce barev"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jedné ruky"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Naslouchátka"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
@@ -1944,6 +1945,10 @@
<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="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 715349d..cae119d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Farvekorrigering"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndstilstand"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 6733faa..8d0d56a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Farbkorrektur"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhandmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradunkel"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörgeräte"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
@@ -1942,6 +1943,10 @@
<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="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 5c57f95..effa751 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Διόρθωση χρωμάτων"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Λειτουργία ενός χεριού"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Επιπλέον μείωση φωτεινότητας"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Συσκευές ακοής"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 4e26ec2..a83ae5c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Colour correction"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 5e5256c..599d6fc 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Color correction"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +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>
+ <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 6600a4f..c691bb2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Colour correction"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 34438a5..7ec6567 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Colour correction"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 02744a6..b18ee98 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Color correction"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +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>
+ <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 2920b20..22ccd22 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Corrección de colores"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo de una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 7ab1057..f1f43cd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Corrección de color"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo Una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
@@ -1943,6 +1944,10 @@
<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="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 a3b11db..bb969ad 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Värvide korrigeerimine"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ühekäerežiim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Eriti tume"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuuldeseadmed"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
@@ -1942,6 +1943,10 @@
<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="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 32778f0..78a5398 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -75,7 +75,7 @@
<string name="CLIRPermanent" msgid="166443681876381118">"Ezin duzu aldatu deitzailearen identitatearen ezarpena."</string>
<string name="auto_data_switch_title" msgid="3286350716870518297">"<xliff:g id="CARRIERDISPLAY">%s</xliff:g> operadorearen datu-konexiora aldatu zara"</string>
<string name="auto_data_switch_content" msgid="803557715007110959">"Ezarpenak atalean alda dezakezu aukera hori"</string>
- <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorreko datu-zerbitzurik"</string>
+ <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorretarako datu-zerbitzurik"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Ezin da egin larrialdi-deirik"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ez dago ahots-deien zerbitzurik"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"Ez dago ahozko zerbitzurik eta ezin da egin larrialdi-deirik"</string>
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Koloreen zuzenketa"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Esku bakarreko modua"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Are ilunago"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audifonoak"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bi bolumen-botoiak hiru segundoz"</string>
@@ -1942,6 +1943,10 @@
<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="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 1bdba0b..9721cfc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"تصحیح رنگ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"حالت یکدستی"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"بسیار کمنور"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"دستگاههای کمکشنوایی"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> روشن شد."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> خاموش شد."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
@@ -1942,6 +1943,10 @@
<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="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 43f4172..a4b3568 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Värinkorjaus"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Yhden käden moodi"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Erittäin himmeä"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuulolaitteet"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
@@ -1942,6 +1943,10 @@
<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="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 31c96f1..8cc239e 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correction des couleurs"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode Une main"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Très sombre"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez les deux touches de volume enfoncées pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 dc3e503..db14f84 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correction des couleurs"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode une main"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Encore moins lumineux"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Prothèses auditives"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 1d014737..e655e69 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Corrección da cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo dunha soa man"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 76fb45f..feb3e9f 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"રંગ સુધારણા"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"એક-હાથે વાપરો મોડ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"એક્સ્ટ્રા ડિમ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"સાંભળવામાં સહાય કરતા ડિવાઇસ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
@@ -1942,6 +1943,10 @@
<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="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 155f254..c6d26a2 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"रंग में सुधार करने की सुविधा"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"सुनने में मदद करने वाले डिवाइस"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
@@ -1942,6 +1943,10 @@
<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="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 7de0b31..b1a6153 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Korekcija boja"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni uređaji"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 955739f..951336c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Színjavítás"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Egykezes mód"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extrasötét"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hallásjavító eszközök"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
@@ -1942,6 +1943,10 @@
<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="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 3a96b70..29c1121 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Գունաշտկում"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Մեկ ձեռքի ռեժիմ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Հավելյալ խամրեցում"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Լսողական սարքեր"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացավ։"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունն անջատվեց։"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
@@ -1942,6 +1943,10 @@
<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="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 20e7f9a..d09926d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Koreksi warna"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode satu tangan"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra redup"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Alat bantu dengar"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 e230406..0057e19 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1708,6 +1708,8 @@
<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="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>
@@ -1942,6 +1944,10 @@
<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="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 3537519..4ba4b29 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correzione del colore"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modalità a una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Attenuazione extra"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Apparecchi acustici"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 2dd23ac..7bb43b0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"תיקון צבע"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"מצב שימוש ביד אחת"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"מעומעם במיוחד"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"מכשירי שמיעה"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 8f618c5..79bd6cb 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"色補正"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"片手モード"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"さらに輝度を下げる"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"補聴器"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
@@ -1942,6 +1943,10 @@
<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="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 2060c83..f173973 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ფერთა კორექცია"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ცალი ხელის რეჟიმი"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"დამატებითი დაბინდვა"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"სმენის აპარატები"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
@@ -1942,6 +1943,10 @@
<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="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 9015e1a..b8aa264 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Түсті түзету"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бір қолмен басқару режимі"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Экранды қарайту"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Есту аппараттары"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
@@ -1942,6 +1943,10 @@
<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="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 1a8508f..44b6137 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ការកែតម្រូវពណ៌"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"មុខងារប្រើដៃម្ខាង"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ពន្លឺតិចខ្លាំង"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ឧបករណ៍ស្តាប់"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 3d8301c..1e2a5fa 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ಒಂದು ಕೈ ಮೋಡ್"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ಇನ್ನಷ್ಟು ಮಬ್ಬು"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
@@ -1942,6 +1943,10 @@
<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="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 3448b36..dbcf849 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"색상 보정"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 모드"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"더 어둡게"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"보청기"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
@@ -1942,6 +1943,10 @@
<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="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 7168a60..edb0886 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -261,7 +261,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Учак режими"</string>
<string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"Учак режими КҮЙҮК"</string>
<string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"Учак режими ӨЧҮК"</string>
- <string name="global_action_settings" msgid="4671878836947494217">"Жөндөөлөр"</string>
+ <string name="global_action_settings" msgid="4671878836947494217">"Параметрлер"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Жардам"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Үн жардамчысы"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Бекем кулпулоо"</string>
@@ -663,7 +663,7 @@
<string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Жүзүңүздүн үлгүсүн өчүрүү үчүн басып, жаңы үлгүнү кошуңуз"</string>
<string name="face_setup_notification_title" msgid="8843461561970741790">"Жүзүнөн таанып ачууну тууралоо"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Телефонуңузду карап туруп эле кулпусун ачып алыңыз"</string>
- <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Жүзүнөн таанып ачуу функциясын колдонуу үчүн Жөндөөлөр > Купуялык бөлүмүнө өтүп, "<b>"Камераны колдонууну"</b>" күйгүзүңүз"</string>
+ <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Жүзүнөн таанып ачуу функциясын колдонуу үчүн Параметрлер > Купуялык бөлүмүнө өтүп, "<b>"Камераны колдонууну"</b>" күйгүзүңүз"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Кулпусун ачуунун көбүрөөк жолдорун жөндөңүз"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Манжа изин кошуу үчүн басыңыз"</string>
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Кулпуланган түзмөктү манжа изи менен ачуу"</string>
@@ -1621,7 +1621,7 @@
<string name="media_route_chooser_title" msgid="6646594924991269208">"Түзмөккө туташуу"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Тышкы экранга чыгаруу"</string>
<string name="media_route_chooser_searching" msgid="6119673534251329535">"Түзмөктөр изделүүдө..."</string>
- <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Жөндөөлөр"</string>
+ <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Параметрлер"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Ажыратуу"</string>
<string name="media_route_status_scanning" msgid="8045156315309594482">"Скандоодо..."</string>
<string name="media_route_status_connecting" msgid="5845597961412010540">"Туташууда..."</string>
@@ -1680,10 +1680,10 @@
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Параметрлер > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Параметрлер > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Жок"</string>
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"КҮЙҮК"</string>
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Түстөрдү тууралоо"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бир кол режими"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Кошумча караңгылатуу"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Угуу түзмөктөрү"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
@@ -1942,6 +1943,10 @@
<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="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 +2071,7 @@
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Кийинчерээк эскертүү"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Жабуу"</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"Тутум"</string>
- <string name="notification_app_name_settings" msgid="9088548800899952531">"Жөндөөлөр"</string>
+ <string name="notification_app_name_settings" msgid="9088548800899952531">"Параметрлер"</string>
<string name="notification_appops_camera_active" msgid="8177643089272352083">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="581333393214739332">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"экрандагы башка терезелердин үстүнөн көрсөтүлүүдө"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index e5b4b45..1874d27 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ການແກ້ໄຂສີ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ໂໝດມືດຽວ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ຫຼຸດແສງເປັນພິເສດ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 7292bbb..b0c481e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Spalvų taisymas"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienos rankos režimas"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Itin blanku"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Klausos įrenginiai"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
@@ -1944,6 +1945,10 @@
<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="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 5a5d70e..3aca9f8 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Krāsu korekcija"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienas rokas režīms"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Papildu aptumšošana"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dzirdes aparāti"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma pogas un turiet tos trīs sekundes."</string>
@@ -1943,6 +1944,10 @@
<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="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 9826e9a..28d5969 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Корекција на боите"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим со една рака"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнително затемнување"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни помагала"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е вклучена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е исклучена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 cf65fdd..4076c68 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"നിറം ശരിയാക്കൽ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ഒറ്റക്കൈ മോഡ്"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"കൂടുതൽ ഡിം ചെയ്യൽ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ശ്രവണ ഉപകരണങ്ങൾ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"വോളിയം കീകൾ പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കി."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"വോളിയം കീകൾ അമർത്തിപ്പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫാക്കി."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
@@ -1942,6 +1943,10 @@
<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="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 bbfff4a..28fa200 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Өнгөний засвар"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Нэг гарын горим"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Хэт бүүдгэр"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Сонсголын төхөөрөмжүүд"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаалаа."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраалаа."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
@@ -1942,6 +1943,10 @@
<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="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 06bb79f..d0d9da3 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"रंग सुधारणा"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एकहाती मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"आणखी डिम"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवणयंत्र डिव्हाइस"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
@@ -1942,6 +1943,10 @@
<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="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 c6b9210..3c0675b 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Pembetulan warna"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mod sebelah tangan"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Amat malap"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Peranti pendengaran"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 7e113a5..9c1f5ff 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"အရောင် အမှန်ပြင်ခြင်း"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"လက်တစ်ဖက်သုံးမုဒ်"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ပိုမှိန်ခြင်း"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"နားကြားကိရိယာ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
@@ -1942,6 +1943,10 @@
<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="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 922f8f7..1d231fe 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Fargekorrigering"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndsmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dimmet"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 b8f8dd9..54c24b5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"रङ सच्याउने सुविधा"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
@@ -1942,6 +1943,10 @@
<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="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 aa6d168..da34559 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Kleurcorrectie"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bediening met 1 hand"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dimmen"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hoortoestellen"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat aan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat uit."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
@@ -1942,6 +1943,10 @@
<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="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 b415908..5cb0b9d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ଏକ-ହାତ ମୋଡ୍"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ଅତ୍ୟଧିକ ଡିମ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
@@ -1942,6 +1943,10 @@
<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="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 467a509..de05d46 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"ਰੰਗ ਸੁਧਾਈ"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -1942,6 +1943,10 @@
<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="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 f8b7753..9e0269b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Korekcja kolorów"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tryb jednej ręki"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatkowe przyciemnienie"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Urządzenia słuchowe"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1944,6 +1945,10 @@
<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="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 9e182b4..ce1f686 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1531,7 +1531,7 @@
<string name="add_account_button_label" msgid="322390749416414097">"Adicionar conta"</string>
<string name="number_picker_increment_button" msgid="7621013714795186298">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="5116948444762708204">"Diminuir"</string>
- <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e mantenha pressionado."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e pressione."</string>
<string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Deslize para cima para aumentar e para baixo para diminuir."</string>
<string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Aumentar minuto"</string>
<string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Diminuir minuto"</string>
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer a tela"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 ee48973..66bd560 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correção da cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mais escuro"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"prima sem soltar as teclas de volume durante três segundos para usar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1943,6 +1944,10 @@
<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="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 9e182b4..ce1f686 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1531,7 +1531,7 @@
<string name="add_account_button_label" msgid="322390749416414097">"Adicionar conta"</string>
<string name="number_picker_increment_button" msgid="7621013714795186298">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="5116948444762708204">"Diminuir"</string>
- <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e mantenha pressionado."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e pressione."</string>
<string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Deslize para cima para aumentar e para baixo para diminuir."</string>
<string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Aumentar minuto"</string>
<string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Diminuir minuto"</string>
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer a tela"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 18a8fcb..9663982 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Corecția culorilor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modul cu o mână"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminozitate redusă suplimentar"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparate auditive"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apasă ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 18c2150..ba548b3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Коррекция цвета"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим управления одной рукой"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнительное уменьшение яркости"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слуховые аппараты"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" отключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
@@ -1944,6 +1945,10 @@
<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="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 301e592..0363b0d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"වර්ණ නිවැරදි කිරීම"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"තනි අත් ප්රකාරය"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"තවත් අඳුරු"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ශ්රවණ උපාංග"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මකයි."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිතයි."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
@@ -1942,6 +1943,10 @@
<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="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 b4da379..e84bc83 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Úprava farieb"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednej ruky"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mimoriadne stmavenie"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Načúvacie zariadenia"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
@@ -1944,6 +1945,10 @@
<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="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 a076d40..52bef0b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Popravljanje barv"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enoročni način"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjen zaslon"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
@@ -1944,6 +1945,10 @@
<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="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 4b0fda9..d691fd0 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Korrigjimi i ngjyrës"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modaliteti i përdorimit me një dorë"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Shumë më i zbehtë"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Pajisjet e dëgjimit"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 7c5a570..aab16eb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1709,6 +1709,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Корекција боја"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим једном руком"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додатно затамњено"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни апарати"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1943,6 +1944,10 @@
<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="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 4a21b76..125999b 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Färgkorrigering"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhandsläge"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradimmat"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörapparater"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 d72eb30..5cf2f77 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Usahihishaji wa rangi"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Hali ya kutumia kwa mkono mmoja"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Kipunguza mwangaza zaidi"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Vifaa vya kusaidia kusikia"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 41279f6..8f576ab 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"கலர் கரெக்ஷன்"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ஒற்றைக் கைப் பயன்முறை"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"செவித்துணைக் கருவிகள்"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
@@ -1942,6 +1943,10 @@
<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="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 b31f920..3cf745b 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"కలర్ కరెక్షన్"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ఎక్స్ట్రా డిమ్"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"వినికిడి పరికరం"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
@@ -1942,6 +1943,10 @@
<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="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 843cd29..4afe454 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"การแก้สี"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"โหมดมือเดียว"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"หรี่แสงเพิ่มเติม"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"เครื่องช่วยฟัง"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 f4e79d7..e808d56 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Pagtatama ng kulay"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Hand mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Mga hearing device"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 ae38880..5d471b3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Renk düzeltme"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tek El modu"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra loş"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"İşitme cihazları"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
@@ -1942,6 +1943,10 @@
<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="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 27cf840..1620c8f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1710,6 +1710,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Корекція кольору"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим керування однією рукою"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додаткове зменшення яскравості"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухові апарати"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
@@ -1944,6 +1945,10 @@
<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="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 0acea52..2b5b2f1 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"رنگ کی اصلاح"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ایک ہاتھ کی وضع"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی مدھم"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعتی آلات"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
@@ -1942,6 +1943,10 @@
<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="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-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e30baba..6a88112 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Ranglarni tuzatish"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ixcham rejim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eshitish qurilmalari"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string>
@@ -1942,6 +1943,8 @@
<string name="work_mode_off_title" msgid="961171256005852058">"Ishga oid ilovalar yoqilsinmi?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Ishga oid ilovalaringiz va bildirishnomalarga ruxsat oling"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string>
+ <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Favqulodda holat"</string>
+ <string name="work_mode_dialer_off_message" msgid="2193299184850387465">"Ishga oid ilovalaringiz va chaqiruvlarga ruxsat oling"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b589b24..258d4ce 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -830,7 +830,7 @@
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"Nhà riêng"</item>
<item msgid="7740243458912727194">"Di động"</item>
- <item msgid="8526146065496663766">"Cơ quan"</item>
+ <item msgid="8526146065496663766">"Nơi làm việc"</item>
<item msgid="8150904584178569699">"Số fax cơ quan"</item>
<item msgid="4537253139152229577">"Số fax nhà riêng"</item>
<item msgid="6751245029698664340">"Số máy nhắn tin"</item>
@@ -839,24 +839,24 @@
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"Nhà riêng"</item>
- <item msgid="435564470865989199">"Cơ quan"</item>
+ <item msgid="435564470865989199">"Nơi làm việc"</item>
<item msgid="4199433197875490373">"Khác"</item>
<item msgid="3233938986670468328">"Tùy chỉnh"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="3861463339764243038">"Nhà riêng"</item>
- <item msgid="5472578890164979109">"Cơ quan"</item>
+ <item msgid="5472578890164979109">"Nơi làm việc"</item>
<item msgid="5718921296646594739">"Khác"</item>
<item msgid="5523122236731783179">"Tùy chỉnh"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="588088543406993772">"Nhà riêng"</item>
- <item msgid="5503060422020476757">"Cơ quan"</item>
+ <item msgid="5503060422020476757">"Nơi làm việc"</item>
<item msgid="2530391194653760297">"Khác"</item>
<item msgid="7640927178025203330">"Tùy chỉnh"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="6144047813304847762">"Cơ quan"</item>
+ <item msgid="6144047813304847762">"Nơi làm việc"</item>
<item msgid="7402720230065674193">"Khác"</item>
<item msgid="808230403067569648">"Tùy chỉnh"</item>
</string-array>
@@ -873,7 +873,7 @@
<string name="phoneTypeCustom" msgid="5120365721260686814">"Tùy chỉnh"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"Nhà riêng"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"Di động"</string>
- <string name="phoneTypeWork" msgid="6604967163358864607">"Cơ quan"</string>
+ <string name="phoneTypeWork" msgid="6604967163358864607">"Nơi làm việc"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"Số fax cơ quan"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"Số fax nhà riêng"</string>
<string name="phoneTypePager" msgid="576402072263522767">"Số máy nhắn tin"</string>
@@ -897,16 +897,16 @@
<string name="eventTypeOther" msgid="530671238533887997">"Khác"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"Tùy chỉnh"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"Nhà riêng"</string>
- <string name="emailTypeWork" msgid="2020095414401882111">"Cơ quan"</string>
+ <string name="emailTypeWork" msgid="2020095414401882111">"Nơi làm việc"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"Khác"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"Di Động"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">"Tùy chỉnh"</string>
<string name="postalTypeHome" msgid="7562272480949727912">"Nhà riêng"</string>
- <string name="postalTypeWork" msgid="8553425424652012826">"Cơ quan"</string>
+ <string name="postalTypeWork" msgid="8553425424652012826">"Nơi làm việc"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"Khác"</string>
<string name="imTypeCustom" msgid="5653384545085765570">"Tùy chỉnh"</string>
<string name="imTypeHome" msgid="6996507981044278216">"Nhà riêng"</string>
- <string name="imTypeWork" msgid="2099668940169903123">"Cơ quan"</string>
+ <string name="imTypeWork" msgid="2099668940169903123">"Nơi làm việc"</string>
<string name="imTypeOther" msgid="8068447383276219810">"Khác"</string>
<string name="imProtocolCustom" msgid="4437878287653764692">"Tùy chỉnh"</string>
<string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string>
@@ -918,7 +918,7 @@
<string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
<string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
- <string name="orgTypeWork" msgid="8684458700669564172">"Cơ quan"</string>
+ <string name="orgTypeWork" msgid="8684458700669564172">"Nơi làm việc"</string>
<string name="orgTypeOther" msgid="5450675258408005553">"Khác"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"Tùy chỉnh"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"Tùy chỉnh"</string>
@@ -938,7 +938,7 @@
<string name="relationTypeSpouse" msgid="6916682664436031703">"Vợ/chồng"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">"Tùy chỉnh"</string>
<string name="sipAddressTypeHome" msgid="5918441930656878367">"Nhà riêng"</string>
- <string name="sipAddressTypeWork" msgid="7873967986701216770">"Cơ quan"</string>
+ <string name="sipAddressTypeWork" msgid="7873967986701216770">"Nơi làm việc"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"Khác"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"Không tìm thấy ứng dụng nào để xem liên hệ này."</string>
<string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"Nhập mã PIN"</string>
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Chỉnh màu"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Chế độ một tay"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Siêu tối"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Thiết bị trợ thính"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 a0ede11..9b998c1 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"色彩校正"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"单手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"极暗"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助听设备"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 3fcf138..065968c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"色彩校正"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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 69e8c13..fd94101 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"色彩校正"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
@@ -1942,6 +1943,10 @@
<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="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 789f5c4..2d17ae2 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1708,6 +1708,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Ukulungiswa kombala"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Imodi yesandla esisodwa"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ukufiphaza okwengeziwe"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Amadivayizi okuzwa"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1942,6 +1943,10 @@
<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="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/config.xml b/core/res/res/values/config.xml
index 6d21fb6..c3ebef0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -560,6 +560,10 @@
rotations as the default behavior. -->
<bool name="config_allowAllRotations">false</bool>
+ <!-- If false and config_allowAllRotations is false, the screen will rotate to the natural
+ orientation of the device when the auto-rotate policy is toggled. -->
+ <bool name="config_useCurrentRotationOnRotationLockChange">false</bool>
+
<!-- If true, the direction rotation is applied to get to an application's requested
orientation is reversed. Normally, the model is that landscape is
clockwise from portrait; thus on a portrait device an app requesting
@@ -4464,6 +4468,9 @@
<!-- Allow SystemUI to show the shutdown dialog -->
<bool name="config_showSysuiShutdown">true</bool>
+ <!-- Flag indicating whether seamless refresh rate switching is supported by a device. -->
+ <bool name="config_supportsSeamlessRefreshRateSwitching">true</bool>
+
<!-- The stable device width and height in pixels. If these aren't set to a positive number
then the device will use the width and height of the default display the first time it's
booted. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2abb0d8..89a28d5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1668,6 +1668,7 @@
<java-symbol type="attr" name="dialogTitleDecorLayout" />
<java-symbol type="attr" name="dialogTitleIconsDecorLayout" />
<java-symbol type="bool" name="config_allowAllRotations" />
+ <java-symbol type="bool" name="config_useCurrentRotationOnRotationLockChange"/>
<java-symbol type="bool" name="config_annoy_dianne" />
<java-symbol type="bool" name="config_startDreamImmediatelyOnDock" />
<java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
@@ -3822,6 +3823,7 @@
<java-symbol type="id" name="messaging_group_icon_container" />
<java-symbol type="id" name="messaging_group_sending_progress" />
<java-symbol type="id" name="messaging_group_sending_progress_container" />
+ <java-symbol type="bool" name="config_supportsSeamlessRefreshRateSwitching" />
<java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
<java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
diff --git a/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java
new file mode 100644
index 0000000..982ad63
--- /dev/null
+++ b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.app;
+
+import static android.app.BackgroundStartPrivileges.ALLOW_BAL;
+import static android.app.BackgroundStartPrivileges.ALLOW_FGS;
+import static android.app.BackgroundStartPrivileges.NONE;
+import static android.app.BackgroundStartPrivileges.allowBackgroundActivityStarts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Binder;
+import android.os.IBinder;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BackgroundStartPrivilegesTest {
+
+ private static final IBinder BINDER_A = new Binder();
+ private static final IBinder BINDER_B = new Binder();
+ private static final BackgroundStartPrivileges BSP_ALLOW_A =
+ allowBackgroundActivityStarts(BINDER_A);
+ private static final BackgroundStartPrivileges BSP_ALLOW_B =
+ allowBackgroundActivityStarts(BINDER_B);
+
+ @Test
+ public void backgroundStartPrivilege_getters_work() {
+ assertThat(ALLOW_BAL.getOriginatingToken()).isNull();
+ assertThat(ALLOW_BAL.allowsBackgroundActivityStarts()).isEqualTo(true);
+ assertThat(ALLOW_BAL.allowsBackgroundFgsStarts()).isEqualTo(true);
+ assertThat(ALLOW_BAL.allowsAny()).isEqualTo(true);
+ assertThat(ALLOW_BAL.allowsNothing()).isEqualTo(false);
+
+ assertThat(ALLOW_FGS.getOriginatingToken()).isNull();
+ assertThat(ALLOW_FGS.allowsBackgroundActivityStarts()).isEqualTo(false);
+ assertThat(ALLOW_FGS.allowsBackgroundFgsStarts()).isEqualTo(true);
+ assertThat(ALLOW_FGS.allowsAny()).isEqualTo(true);
+ assertThat(ALLOW_FGS.allowsNothing()).isEqualTo(false);
+
+ assertThat(NONE.getOriginatingToken()).isNull();
+ assertThat(NONE.allowsBackgroundActivityStarts()).isEqualTo(false);
+ assertThat(NONE.allowsBackgroundFgsStarts()).isEqualTo(false);
+ assertThat(NONE.allowsAny()).isEqualTo(false);
+ assertThat(NONE.allowsNothing()).isEqualTo(true);
+
+ assertThat(BSP_ALLOW_A.getOriginatingToken()).isEqualTo(BINDER_A);
+ assertThat(BSP_ALLOW_A.allowsBackgroundActivityStarts()).isEqualTo(true);
+ assertThat(BSP_ALLOW_A.allowsBackgroundFgsStarts()).isEqualTo(true);
+ assertThat(BSP_ALLOW_A.allowsAny()).isEqualTo(true);
+ assertThat(BSP_ALLOW_A.allowsNothing()).isEqualTo(false);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_toString_returnsSomething() {
+ assertThat(ALLOW_BAL.toString()).isNotEmpty();
+ assertThat(ALLOW_FGS.toString()).isNotEmpty();
+ assertThat(NONE.toString()).isNotEmpty();
+ assertThat(BSP_ALLOW_A.toString()).isNotEmpty();
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeAA_resultsInA() {
+ assertThat(BSP_ALLOW_A.merge(BSP_ALLOW_A)).isEqualTo(BSP_ALLOW_A);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeAB_resultsInAllowBal() {
+ assertThat(BSP_ALLOW_A.merge(BSP_ALLOW_B)).isEqualTo(ALLOW_BAL);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeAwithAllowBal_resultsInAllowBal() {
+ assertThat(BSP_ALLOW_A.merge(ALLOW_BAL)).isEqualTo(ALLOW_BAL);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeAwithAllowFgs_resultsInAllowBal() {
+ assertThat(BSP_ALLOW_A.merge(ALLOW_FGS)).isEqualTo(ALLOW_BAL);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeAwithNone_resultsInA() {
+ assertThat(BSP_ALLOW_A.merge(NONE)).isEqualTo(BSP_ALLOW_A);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeManyWithDifferentToken_resultsInAllowBal() {
+ assertThat(BackgroundStartPrivileges.merge(
+ Arrays.asList(BSP_ALLOW_A, BSP_ALLOW_B, NONE, BSP_ALLOW_A, ALLOW_FGS)))
+ .isEqualTo(ALLOW_BAL);
+ }
+
+ @Test
+ public void backgroundStartPrivilege_mergeManyWithSameToken_resultsInAllowBal() {
+ assertThat(BackgroundStartPrivileges.merge(
+ Arrays.asList(BSP_ALLOW_A, BSP_ALLOW_A, BSP_ALLOW_A, BSP_ALLOW_A)))
+ .isEqualTo(BSP_ALLOW_A);
+ }
+}
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java b/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java
new file mode 100644
index 0000000..76f4171
--- /dev/null
+++ b/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.text;
+
+import static android.text.Layout.Alignment.ALIGN_NORMAL;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.text.method.OffsetMapping;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DynamicLayoutOffsetMappingTest {
+ private static final int WIDTH = 10000;
+ private static final TextPaint sTextPaint = new TextPaint();
+
+ @Test
+ public void textWithOffsetMapping() {
+ final String text = "abcde";
+ final SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ final CharSequence transformedText = new TestOffsetMapping(spannable, 2, "\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ assertThat(transformedText.toString()).isEqualTo("ab\ncde");
+ assertLineRange(layout, /* lineBreaks */ 0, 3, 6);
+ }
+
+ @Test
+ public void textWithOffsetMapping_deletion() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ final CharSequence transformedText =
+ new TestOffsetMapping(spannable, 3, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ // delete character 'c', original text becomes "abdef"
+ spannable.delete(2, 3);
+ assertThat(transformedText.toString()).isEqualTo("ab\n\ndef");
+ assertLineRange(layout, /* lineBreaks */ 0, 3, 4, 7);
+
+ // delete character 'd', original text becomes "abef"
+ spannable.delete(2, 3);
+ assertThat(transformedText.toString()).isEqualTo("ab\n\nef");
+ assertLineRange(layout, /* lineBreaks */ 0, 3, 4, 6);
+
+ // delete "be", original text becomes "af"
+ spannable.delete(1, 3);
+ assertThat(transformedText.toString()).isEqualTo("a\n\nf");
+ assertLineRange(layout, /* lineBreaks */ 0, 2, 3, 4);
+ }
+
+ @Test
+ public void textWithOffsetMapping_insertion() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ final CharSequence transformedText = new TestOffsetMapping(spannable, 3, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ spannable.insert(3, "x");
+ assertThat(transformedText.toString()).isEqualTo("abcx\n\ndef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 9);
+
+ spannable.insert(5, "x");
+ assertThat(transformedText.toString()).isEqualTo("abcx\n\ndxef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 10);
+ }
+
+ @Test
+ public void textWithOffsetMapping_replace() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ final CharSequence transformedText = new TestOffsetMapping(spannable, 3, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ spannable.replace(2, 4, "xx");
+ assertThat(transformedText.toString()).isEqualTo("abxx\n\nef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 8);
+ }
+
+ private void assertLineRange(Layout layout, int... lineBreaks) {
+ final int lineCount = lineBreaks.length - 1;
+ assertThat(layout.getLineCount()).isEqualTo(lineCount);
+ for (int line = 0; line < lineCount; ++line) {
+ assertThat(layout.getLineStart(line)).isEqualTo(lineBreaks[line]);
+ }
+ assertThat(layout.getLineEnd(lineCount - 1)).isEqualTo(lineBreaks[lineCount]);
+ }
+
+ /**
+ * A test TransformedText that inserts some text at the given offset.
+ */
+ private static class TestOffsetMapping implements OffsetMapping, CharSequence {
+ private final int mOriginalInsertOffset;
+ private final CharSequence mOriginal;
+ private final CharSequence mInsertText;
+ TestOffsetMapping(CharSequence original, int insertOffset,
+ CharSequence insertText) {
+ mOriginal = original;
+ if (mOriginal instanceof Spannable) {
+ ((Spannable) mOriginal).setSpan(INSERT_POINT, insertOffset, insertOffset,
+ Spanned.SPAN_POINT_POINT);
+ }
+ mOriginalInsertOffset = insertOffset;
+ mInsertText = insertText;
+ }
+
+ private int getInsertOffset() {
+ if (mOriginal instanceof Spannable) {
+ return ((Spannable) mOriginal).getSpanStart(INSERT_POINT);
+ }
+ return mOriginalInsertOffset;
+ }
+
+ @Override
+ public int originalToTransformed(int offset, int strategy) {
+ final int insertOffset = getInsertOffset();
+ if (strategy == OffsetMapping.MAP_STRATEGY_CURSOR && offset == insertOffset) {
+ return offset;
+ }
+ if (offset < getInsertOffset()) {
+ return offset;
+ }
+ return offset + mInsertText.length();
+ }
+
+ @Override
+ public int transformedToOriginal(int offset, int strategy) {
+ final int insertOffset = getInsertOffset();
+ if (offset < insertOffset) {
+ return offset;
+ }
+ if (offset < insertOffset + mInsertText.length()) {
+ return insertOffset;
+ }
+ return offset - mInsertText.length();
+ }
+
+ @Override
+ public void originalToTransformed(TextUpdate textUpdate) {
+ final int insertOffset = getInsertOffset();
+ if (textUpdate.where <= insertOffset) {
+ if (textUpdate.where + textUpdate.before > insertOffset) {
+ textUpdate.before += mInsertText.length();
+ textUpdate.after += mInsertText.length();
+ }
+ } else {
+ textUpdate.where += mInsertText.length();
+ }
+ }
+
+ @Override
+ public int length() {
+ return mOriginal.length() + mInsertText.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ final int insertOffset = getInsertOffset();
+ if (index < insertOffset) {
+ return mOriginal.charAt(index);
+ }
+ if (index < insertOffset + mInsertText.length()) {
+ return mInsertText.charAt(index - insertOffset);
+ }
+ return mOriginal.charAt(index - mInsertText.length());
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int index = start; index < end; ++index) {
+ stringBuilder.append(charAt(index));
+ }
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int index = 0; index < length(); ++index) {
+ stringBuilder.append(charAt(index));
+ }
+ return stringBuilder.toString();
+ }
+
+ static final NoCopySpan INSERT_POINT = new NoCopySpan() { };
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index cc4fbab..f5582d0 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -19,19 +19,30 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.text.GetChars;
import android.text.Layout;
import android.text.PrecomputedText;
+import android.text.method.OffsetMapping;
+import android.text.method.TransformationMethod;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView.BufferType;
@@ -321,6 +332,94 @@
assertEquals("hi", charWrapper.toString());
}
+ @Test
+ @UiThreadTest
+ public void transformedToOriginal_noOffsetMapping() {
+ mTextView = new TextView(mActivity);
+ final String text = "Hello world";
+ mTextView.setText(text);
+ for (int offset = 0; offset < text.length(); ++offset) {
+ assertThat(mTextView.transformedToOriginal(offset, OffsetMapping.MAP_STRATEGY_CURSOR))
+ .isEqualTo(offset);
+ assertThat(mTextView.transformedToOriginal(offset,
+ OffsetMapping.MAP_STRATEGY_CHARACTER)).isEqualTo(offset);
+ }
+ }
+
+ @Test
+ @UiThreadTest
+ public void originalToTransformed_noOffsetMapping() {
+ mTextView = new TextView(mActivity);
+ final String text = "Hello world";
+ mTextView.setText(text);
+ for (int offset = 0; offset < text.length(); ++offset) {
+ assertThat(mTextView.originalToTransformed(offset, OffsetMapping.MAP_STRATEGY_CURSOR))
+ .isEqualTo(offset);
+ assertThat(mTextView.originalToTransformed(offset,
+ OffsetMapping.MAP_STRATEGY_CHARACTER)).isEqualTo(offset);
+ }
+ }
+
+ @Test
+ @UiThreadTest
+ public void originalToTransformed_hasOffsetMapping() {
+ mTextView = new TextView(mActivity);
+ final CharSequence text = "Hello world";
+ final TransformedText transformedText = mock(TransformedText.class);
+ when(transformedText.originalToTransformed(anyInt(), anyInt())).then((invocation) -> {
+ // plus 1 for character strategy and minus 1 for cursor strategy.
+ if ((int) invocation.getArgument(1) == OffsetMapping.MAP_STRATEGY_CHARACTER) {
+ return (int) invocation.getArgument(0) + 1;
+ }
+ return (int) invocation.getArgument(0) - 1;
+ });
+
+ final TransformationMethod transformationMethod =
+ new TestTransformationMethod(transformedText);
+ mTextView.setText(text);
+ mTextView.setTransformationMethod(transformationMethod);
+
+ assertThat(mTextView.originalToTransformed(1, OffsetMapping.MAP_STRATEGY_CHARACTER))
+ .isEqualTo(2);
+ verify(transformedText, times(1))
+ .originalToTransformed(1, OffsetMapping.MAP_STRATEGY_CHARACTER);
+
+ assertThat(mTextView.originalToTransformed(1, OffsetMapping.MAP_STRATEGY_CURSOR))
+ .isEqualTo(0);
+ verify(transformedText, times(1))
+ .originalToTransformed(1, OffsetMapping.MAP_STRATEGY_CURSOR);
+ }
+
+ @Test
+ @UiThreadTest
+ public void transformedToOriginal_hasOffsetMapping() {
+ mTextView = new TextView(mActivity);
+ final CharSequence text = "Hello world";
+ final TransformedText transformedText = mock(TransformedText.class);
+ when(transformedText.transformedToOriginal(anyInt(), anyInt())).then((invocation) -> {
+ // plus 1 for character strategy and minus 1 for cursor strategy.
+ if ((int) invocation.getArgument(1) == OffsetMapping.MAP_STRATEGY_CHARACTER) {
+ return (int) invocation.getArgument(0) + 1;
+ }
+ return (int) invocation.getArgument(0) - 1;
+ });
+
+ final TransformationMethod transformationMethod =
+ new TestTransformationMethod(transformedText);
+ mTextView.setText(text);
+ mTextView.setTransformationMethod(transformationMethod);
+
+ assertThat(mTextView.transformedToOriginal(1, OffsetMapping.MAP_STRATEGY_CHARACTER))
+ .isEqualTo(2);
+ verify(transformedText, times(1))
+ .transformedToOriginal(1, OffsetMapping.MAP_STRATEGY_CHARACTER);
+
+ assertThat(mTextView.transformedToOriginal(1, OffsetMapping.MAP_STRATEGY_CURSOR))
+ .isEqualTo(0);
+ verify(transformedText, times(1))
+ .transformedToOriginal(1, OffsetMapping.MAP_STRATEGY_CURSOR);
+ }
+
private String createLongText() {
int size = 600 * 1000;
final StringBuilder builder = new StringBuilder(size);
@@ -351,4 +450,24 @@
}
}
}
+
+ private interface TransformedText extends OffsetMapping, CharSequence { }
+
+ private static class TestTransformationMethod implements TransformationMethod {
+ private final CharSequence mTransformedText;
+
+ TestTransformationMethod(CharSequence transformedText) {
+ this.mTransformedText = transformedText;
+ }
+
+ @Override
+ public CharSequence getTransformation(CharSequence source, View view) {
+ return mTransformedText;
+ }
+
+ @Override
+ public void onFocusChanged(View view, CharSequence sourceText, boolean focused,
+ int direction, Rect previouslyFocusedRect) {
+ }
+ }
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d533805..bf7f3bd 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -465,6 +465,7 @@
<!-- Permission required for CTS test - SystemMediaRouter2Test -->
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
+ <permission name="android.permission.MODIFY_AUDIO_SYSTEM_SETTINGS"/>
<!-- Permission required for CTS test - CallAudioInterceptionTest -->
<permission name="android.permission.CALL_AUDIO_INTERCEPTION"/>
<!-- Permission required for CTS test - CtsPermission5TestCases -->
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index 07d0158..c5d932e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -79,6 +79,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+import androidx.window.extensions.core.util.function.Function;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
import androidx.window.extensions.layout.WindowLayoutInfo;
@@ -563,10 +564,10 @@
SplitAttributes.SplitType.RatioSplitType.splitEqually()
)
).build();
+ final Function<SplitAttributesCalculatorParams, SplitAttributes> calculator =
+ params -> splitAttributes;
- mController.setSplitAttributesCalculator(params -> {
- return splitAttributes;
- });
+ mController.setSplitAttributesCalculator(calculator);
assertEquals(splitAttributes, mPresenter.computeSplitAttributes(taskProperties,
splitPairRule, null /* minDimensionsPair */));
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 5de5365..cddbf469 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 528c51d2..57a8977 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="pip_phone_close" msgid="5783752637260411309">"Жабуу"</string>
<string name="pip_phone_expand" msgid="2579292903468287504">"Жайып көрсөтүү"</string>
- <string name="pip_phone_settings" msgid="5468987116750491918">"Жөндөөлөр"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Параметрлер"</string>
<string name="pip_phone_enter_split" msgid="7042877263880641911">"Экранды бөлүү режимине өтүү"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"Сүрөт ичиндеги сүрөт менюсу"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 8121b20..e85b3c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -232,10 +232,13 @@
if (mBubble.isAppBubble()) {
PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- mBubble.getAppBubbleIntent(),
- PendingIntent.FLAG_MUTABLE,
+ mBubble.getAppBubbleIntent()
+ .addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
+ .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
+ PendingIntent.FLAG_IMMUTABLE,
null);
- mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
+ mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
+ launchBounds);
} else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {
options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index d0aef20..9edfffc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -384,7 +384,7 @@
@Nullable ImeTracker.Token statsToken) {
final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
if (imeSource == null || mImeSourceControl == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
return;
}
final Rect newFrame = imeSource.getFrame();
@@ -407,7 +407,8 @@
}
if ((!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show))
|| (mAnimationDirection == DIRECTION_HIDE && !show)) {
- ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+ ImeTracker.forLogging().onCancelled(
+ statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
return;
}
boolean seek = false;
@@ -451,7 +452,7 @@
mTransactionPool.release(t);
});
mAnimation.setInterpolator(INTERPOLATOR);
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled = false;
@Nullable
@@ -474,7 +475,7 @@
: 1.f;
t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (mAnimationDirection == DIRECTION_SHOW) {
- ImeTracker.get().onProgress(mStatsToken,
+ ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_ANIMATION_RUNNING);
t.show(mImeSourceControl.getLeash());
}
@@ -511,15 +512,15 @@
}
dispatchEndPositioning(mDisplayId, mCancelled, t);
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
- ImeTracker.get().onProgress(mStatsToken,
+ ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_ANIMATION_RUNNING);
t.hide(mImeSourceControl.getLeash());
removeImeSurface();
- ImeTracker.get().onHidden(mStatsToken);
+ ImeTracker.forLogging().onHidden(mStatsToken);
} else if (mAnimationDirection == DIRECTION_SHOW && !mCancelled) {
- ImeTracker.get().onShown(mStatsToken);
+ ImeTracker.forLogging().onShown(mStatsToken);
} else if (mCancelled) {
- ImeTracker.get().onCancelled(mStatsToken,
+ ImeTracker.forLogging().onCancelled(mStatsToken,
ImeTracker.PHASE_WM_ANIMATION_RUNNING);
}
if (DEBUG_IME_VISIBILITY) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index 8759301..9bdda14 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -162,10 +162,12 @@
@Nullable ImeTracker.Token statsToken) {
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
if (listeners == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
for (OnInsetsChangedListener listener : listeners) {
listener.showInsets(types, fromIme, statsToken);
}
@@ -175,10 +177,12 @@
@Nullable ImeTracker.Token statsToken) {
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
if (listeners == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
return;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+ ImeTracker.forLogging().onProgress(
+ statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
for (OnInsetsChangedListener listener : listeners) {
listener.hideInsets(types, fromIme, statsToken);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index fcbf9e0..fa3a6ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -78,6 +78,7 @@
private final Rect mResizingBounds = new Rect();
private final Rect mTempRect = new Rect();
private ValueAnimator mFadeAnimator;
+ private ValueAnimator mScreenshotAnimator;
private int mIconSize;
private int mOffsetX;
@@ -135,8 +136,17 @@
/** Releases the surfaces for split decor. */
public void release(SurfaceControl.Transaction t) {
- if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
- mFadeAnimator.cancel();
+ if (mFadeAnimator != null) {
+ if (mFadeAnimator.isRunning()) {
+ mFadeAnimator.cancel();
+ }
+ mFadeAnimator = null;
+ }
+ if (mScreenshotAnimator != null) {
+ if (mScreenshotAnimator.isRunning()) {
+ mScreenshotAnimator.cancel();
+ }
+ mScreenshotAnimator = null;
}
if (mViewHost != null) {
mViewHost.release();
@@ -238,16 +248,20 @@
/** Stops showing resizing hint. */
public void onResized(SurfaceControl.Transaction t, Runnable animFinishedCallback) {
if (mScreenshot != null) {
+ if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
+ mScreenshotAnimator.cancel();
+ }
+
t.setPosition(mScreenshot, mOffsetX, mOffsetY);
final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
- final ValueAnimator va = ValueAnimator.ofFloat(1, 0);
- va.addUpdateListener(valueAnimator -> {
+ mScreenshotAnimator = ValueAnimator.ofFloat(1, 0);
+ mScreenshotAnimator.addUpdateListener(valueAnimator -> {
final float progress = (float) valueAnimator.getAnimatedValue();
animT.setAlpha(mScreenshot, progress);
animT.apply();
});
- va.addListener(new AnimatorListenerAdapter() {
+ mScreenshotAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mRunningAnimationCount++;
@@ -266,7 +280,7 @@
}
}
});
- va.start();
+ mScreenshotAnimator.start();
}
if (mResizingIconView == null) {
@@ -292,9 +306,6 @@
});
return;
}
-
- // If fade-in animation is running, cancel it and re-run fade-out one.
- mFadeAnimator.cancel();
}
if (mShown) {
fadeOutDecor(animFinishedCallback);
@@ -332,6 +343,11 @@
* directly. */
public void fadeOutDecor(Runnable finishedCallback) {
if (mShown) {
+ // If previous animation is running, just cancel it.
+ if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
+ mFadeAnimator.cancel();
+ }
+
startFadeAnimation(false /* show */, true, finishedCallback);
mShown = false;
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 63b03ab..a839a23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -36,6 +36,7 @@
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
@@ -261,6 +262,11 @@
}
}
+ /** Get number of tasks that are marked as visible */
+ int getVisibleTaskCount() {
+ return mDesktopModeTaskRepository.getVisibleTaskCount();
+ }
+
@NonNull
private WindowContainerTransaction bringDesktopAppsToFront(boolean force) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -438,5 +444,15 @@
executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
DesktopModeController::showDesktopApps);
}
+
+ @Override
+ public int getVisibleTaskCount() throws RemoteException {
+ int[] result = new int[1];
+ executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
+ controller -> result[0] = controller.getVisibleTaskCount(),
+ true /* blocking */
+ );
+ return result[0];
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 600ccc1..47342c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -143,6 +143,13 @@
}
/**
+ * Get number of tasks that are marked as visible
+ */
+ fun getVisibleTaskCount(): Int {
+ return visibleTasks.size
+ }
+
+ /**
* Add (or move if it already exists) the task to the top of the ordered list.
*/
fun addOrMoveFreeformTaskToTop(taskId: Int) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 9165f70..2303325 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -96,6 +96,11 @@
}
}
+ /** Get number of tasks that are marked as visible */
+ fun getVisibleTaskCount(): Int {
+ return desktopModeTaskRepository.getVisibleTaskCount()
+ }
+
/** Move a task with given `taskId` to desktop */
fun moveToDesktop(taskId: Int) {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task) }
@@ -309,5 +314,16 @@
Consumer(DesktopTasksController::showDesktopApps)
)
}
+
+ override fun getVisibleTaskCount(): Int {
+ val result = IntArray(1)
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "getVisibleTaskCount",
+ { controller -> result[0] = controller.getVisibleTaskCount() },
+ true /* blocking */
+ )
+ return result[0]
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 5042bd6..d0739e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -23,4 +23,7 @@
/** Show apps on the desktop */
void showDesktopApps();
+
+ /** Get count of visible desktop tasks */
+ int getVisibleTaskCount();
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
index b189163..8d4a384 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
@@ -125,7 +125,9 @@
cancelScheduledPlacement();
applyPlacement(placement, shouldStash, animationDuration);
} else {
- applyPlacementBounds(mCurrentPlacementBounds, animationDuration);
+ if (mCurrentPlacementBounds != null) {
+ applyPlacementBounds(mCurrentPlacementBounds, animationDuration);
+ }
schedulePinnedStackPlacement(placement, animationDuration);
}
}
@@ -188,7 +190,7 @@
applyPlacementBounds(bounds, animationDuration);
}
- void onPipDismissed() {
+ void reset() {
mCurrentPlacementBounds = null;
mPipTargetBounds = null;
cancelScheduledPlacement();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index fd4fcff..4426423 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -450,18 +450,6 @@
mPipMediaController.registerSessionListenerForCurrentUser();
}
- private void checkIfPinnedTaskAppeared() {
- final TaskInfo pinnedTask = getPinnedTaskInfo();
- ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "%s: checkIfPinnedTaskAppeared(), task=%s", TAG, pinnedTask);
- if (pinnedTask == null || pinnedTask.topActivity == null) return;
- mPinnedTaskId = pinnedTask.taskId;
-
- mPipMediaController.onActivityPinned();
- mActionBroadcastReceiver.register();
- mPipNotificationController.show(pinnedTask.topActivity.getPackageName());
- }
-
private void checkIfPinnedTaskIsGone() {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: onTaskStackChanged()", TAG);
@@ -482,7 +470,7 @@
mTvPipMenuController.closeMenu();
mTvPipBoundsState.resetTvPipState();
- mTvPipBoundsController.onPipDismissed();
+ mTvPipBoundsController.reset();
setState(STATE_NO_PIP);
mPinnedTaskId = NONEXISTENT_TASK_ID;
}
@@ -537,7 +525,16 @@
taskStackListener.addListener(new TaskStackListenerCallback() {
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
- checkIfPinnedTaskAppeared();
+ final TaskInfo pinnedTask = getPinnedTaskInfo();
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onActivityPinned(), task=%s", TAG, pinnedTask);
+ if (pinnedTask == null || pinnedTask.topActivity == null) return;
+ mPinnedTaskId = pinnedTask.taskId;
+
+ mPipMediaController.onActivityPinned();
+ mActionBroadcastReceiver.register();
+ mPipNotificationController.show(pinnedTask.topActivity.getPackageName());
+ mTvPipBoundsController.reset();
mAppOpsListener.onActivityPinned(packageName);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java
index 5c45527..04ae2f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java
@@ -24,12 +24,12 @@
/**
* Algorithm for determining the type of a new starting window on Android TV.
- * For now we always show empty splash screens on Android TV.
+ * For now we do not want to show any splash screens on Android TV.
*/
public class TvStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm {
@Override
public int getSuggestedWindowType(StartingWindowInfo windowInfo) {
- // For now we want to always show empty splash screens on TV.
+ // For now we do not want to show any splash screens on TV.
return STARTING_WINDOW_TYPE_NONE;
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 27fc381a..65923ff 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -22,6 +22,10 @@
<!-- Ensure output directory is empty at the start -->
<option name="run-command" value="rm -rf /sdcard/flicker" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="WMShellFlickerTests.apk"/>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 35cc168..7997a7e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -334,6 +334,41 @@
}
@Test
+ public void testGetVisibleTaskCount_noTasks_returnsZero() {
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
+ RunningTaskInfo task1 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+
+ RunningTaskInfo task2 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */);
+
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testGetVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
+ RunningTaskInfo task1 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+
+ RunningTaskInfo task2 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, false /* visible */);
+
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(1);
+ }
+
+ @Test
public void testHandleTransitionRequest_desktopModeNotActive_returnsNull() {
when(DesktopModeStatus.isActive(any())).thenReturn(false);
WindowContainerTransaction wct = mController.handleRequest(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 1e43a59..45cb3a0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -141,6 +141,36 @@
}
@Test
+ fun getVisibleTaskCount() {
+ // No tasks, count is 0
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+
+ // New task increments count to 1
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Visibility update to same task does not increase count
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Second task visible increments count
+ repo.updateVisibleFreeformTasks(taskId = 2, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(2)
+
+ // Hiding a task decrements count
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Hiding all tasks leaves count at 0
+ repo.updateVisibleFreeformTasks(taskId = 2, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+
+ // Hiding a not existing task, count remains at 0
+ repo.updateVisibleFreeformTasks(taskId = 999, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+ }
+
+ @Test
fun addOrMoveFreeformTaskToTop_didNotExist_addsToTop() {
repo.addOrMoveFreeformTaskToTop(5)
repo.addOrMoveFreeformTaskToTop(6)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 4011d08..f16beee 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -197,6 +197,27 @@
}
@Test
+ fun getVisibleTaskCount_noTasks_returnsZero() {
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(0)
+ }
+
+ @Test
+ fun getVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
+ setUpHomeTask()
+ setUpFreeformTask().also(::markTaskVisible)
+ setUpFreeformTask().also(::markTaskVisible)
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(2)
+ }
+
+ @Test
+ fun getVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
+ setUpHomeTask()
+ setUpFreeformTask().also(::markTaskVisible)
+ setUpFreeformTask().also(::markTaskHidden)
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(1)
+ }
+
+ @Test
fun moveToDesktop() {
val task = setUpFullscreenTask()
controller.moveToDesktop(task)
@@ -224,7 +245,7 @@
assertThat(hierarchyOps).hasSize(3)
assertReorderSequence(homeTask, freeformTask, fullscreenTask)
assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
- .isEqualTo(WINDOWING_MODE_FREEFORM)
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
}
}
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 320d332..c98b87a 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -34,6 +34,7 @@
#include <fcntl.h>
#include <memory>
#include <stdio.h>
+#include <stdint.h>
#include <sys/stat.h>
jfieldID gOptions_justBoundsFieldID;
@@ -142,7 +143,7 @@
}
const size_t size = info.computeByteSize(bitmap->rowBytes());
- if (size > SK_MaxS32) {
+ if (size > INT32_MAX) {
ALOGW("bitmap is too large");
return false;
}
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index 4e2ce91..77fa9dc 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -16,6 +16,7 @@
package android.media;
+import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -318,8 +319,10 @@
* @param ada the device for which volume is to be modified
*/
@SystemApi
- // TODO alternatively require MODIFY_AUDIO_SYSTEM_SETTINGS when defined
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS
+ })
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) {
try {
getService().setDeviceVolume(vi, ada, mPackageName);
@@ -340,8 +343,10 @@
* @param ada the device for which volume is to be retrieved
*/
@SystemApi
- // TODO alternatively require MODIFY_AUDIO_SYSTEM_SETTINGS when defined
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS
+ })
public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
@NonNull AudioDeviceAttributes ada) {
try {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5ee32d6..c06352c 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -106,9 +106,11 @@
void setStreamVolumeWithAttribution(int streamType, int index, int flags,
in String callingPackage, in String attributionTag);
+ @EnforcePermission(anyOf = {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
void setDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
in String callingPackage);
+ @EnforcePermission(anyOf = {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
VolumeInfo getDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
in String callingPackage);
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 98819a3..0198419 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -28,11 +28,11 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* @hide
@@ -140,7 +140,7 @@
*/
public static int getLegacyStreamTypeForStrategyWithAudioAttributes(
@NonNull AudioAttributes audioAttributes) {
- Preconditions.checkNotNull(audioAttributes, "AudioAttributes must not be null");
+ Objects.requireNonNull(audioAttributes, "AudioAttributes must not be null");
for (final AudioProductStrategy productStrategy :
AudioProductStrategy.getAudioProductStrategies()) {
if (productStrategy.supportsAudioAttributes(audioAttributes)) {
@@ -160,6 +160,30 @@
return AudioSystem.STREAM_MUSIC;
}
+ /**
+ * @hide
+ * @param attributes the {@link AudioAttributes} to identify VolumeGroupId with
+ * @param fallbackOnDefault if set, allows to fallback on the default group (e.g. the group
+ * associated to {@link AudioManager#STREAM_MUSIC}).
+ * @return volume group id associated with the given {@link AudioAttributes} if found,
+ * default volume group id if fallbackOnDefault is set
+ * <p>By convention, the product strategy with default attributes will be associated to the
+ * default volume group (e.g. associated to {@link AudioManager#STREAM_MUSIC})
+ * or {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} if not found.
+ */
+ public static int getVolumeGroupIdForAudioAttributes(
+ @NonNull AudioAttributes attributes, boolean fallbackOnDefault) {
+ Objects.requireNonNull(attributes, "attributes must not be null");
+ int volumeGroupId = getVolumeGroupIdForAudioAttributesInt(attributes);
+ if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
+ return volumeGroupId;
+ }
+ if (fallbackOnDefault) {
+ return getVolumeGroupIdForAudioAttributesInt(getDefaultAttributes());
+ }
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+
private static List<AudioProductStrategy> initializeAudioProductStrategies() {
ArrayList<AudioProductStrategy> apsList = new ArrayList<AudioProductStrategy>();
int status = native_list_audio_product_strategies(apsList);
@@ -190,8 +214,8 @@
*/
private AudioProductStrategy(@NonNull String name, int id,
@NonNull AudioAttributesGroup[] aag) {
- Preconditions.checkNotNull(name, "name must not be null");
- Preconditions.checkNotNull(aag, "AudioAttributesGroups must not be null");
+ Objects.requireNonNull(name, "name must not be null");
+ Objects.requireNonNull(aag, "AudioAttributesGroups must not be null");
mName = name;
mId = id;
mAudioAttributesGroups = aag;
@@ -241,7 +265,7 @@
*/
@TestApi
public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return aag.getStreamType();
@@ -258,7 +282,7 @@
*/
@SystemApi
public boolean supportsAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return true;
@@ -291,7 +315,7 @@
*/
@TestApi
public int getVolumeGroupIdForAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return aag.getVolumeGroupId();
@@ -300,6 +324,17 @@
return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
}
+ private static int getVolumeGroupIdForAudioAttributesInt(@NonNull AudioAttributes attributes) {
+ Objects.requireNonNull(attributes, "attributes must not be null");
+ for (AudioProductStrategy productStrategy : getAudioProductStrategies()) {
+ int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
+ if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
+ return volumeGroupId;
+ }
+ }
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -374,8 +409,8 @@
*/
private static boolean attributesMatches(@NonNull AudioAttributes refAttr,
@NonNull AudioAttributes attr) {
- Preconditions.checkNotNull(refAttr, "refAttr must not be null");
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(refAttr, "reference AudioAttributes must not be null");
+ Objects.requireNonNull(attr, "requester's AudioAttributes must not be null");
String refFormattedTags = TextUtils.join(";", refAttr.getTags());
String cliFormattedTags = TextUtils.join(";", attr.getTags());
if (refAttr.equals(DEFAULT_ATTRIBUTES)) {
diff --git a/media/java/android/media/projection/TEST_MAPPING b/media/java/android/media/projection/TEST_MAPPING
new file mode 100644
index 0000000..a792498
--- /dev/null
+++ b/media/java/android/media/projection/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "MediaProjectionTests",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
+}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index e6da1a3..e8127df 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -119,16 +119,16 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
- VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
- VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY, VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE,
- VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION,
- VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED,
- VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED,
- VIDEO_UNAVAILABLE_REASON_CAS_NO_LICENSE, VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED,
- VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION, VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING,
- VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD, VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE,
- VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID, VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT,
- VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING, VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN})
+ VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
+ VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY, VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED,
+ VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE,
+ VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION,
+ VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED,
+ VIDEO_UNAVAILABLE_REASON_CAS_NO_LICENSE, VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED,
+ VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION, VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING,
+ VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD, VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE,
+ VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID, VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT,
+ VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING, VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN})
public @interface VideoUnavailableReason {}
/**
diff --git a/media/java/android/media/tv/tuner/DemuxCapabilities.java b/media/java/android/media/tv/tuner/DemuxCapabilities.java
index 14a9144..19cd023a 100644
--- a/media/java/android/media/tv/tuner/DemuxCapabilities.java
+++ b/media/java/android/media/tv/tuner/DemuxCapabilities.java
@@ -36,8 +36,14 @@
public class DemuxCapabilities {
/** @hide */
- @IntDef(value = {Filter.TYPE_TS, Filter.TYPE_MMTP, Filter.TYPE_IP, Filter.TYPE_TLV,
- Filter.TYPE_ALP})
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ Filter.TYPE_UNDEFINED,
+ Filter.TYPE_TS,
+ Filter.TYPE_MMTP,
+ Filter.TYPE_IP,
+ Filter.TYPE_TLV,
+ Filter.TYPE_ALP,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FilterCapabilities {}
@@ -51,14 +57,16 @@
private final int mPesFilterCount;
private final int mPcrFilterCount;
private final long mSectionFilterLength;
- private final int mFilterCaps;
+ private final @FilterCapabilities int mFilterCaps;
+ private final @FilterCapabilities int[] mFilterCapsList;
private final int[] mLinkCaps;
private final boolean mSupportTimeFilter;
// Used by JNI
private DemuxCapabilities(int demuxCount, int recordCount, int playbackCount, int tsFilterCount,
int sectionFilterCount, int audioFilterCount, int videoFilterCount, int pesFilterCount,
- int pcrFilterCount, long sectionFilterLength, int filterCaps, int[] linkCaps,
+ int pcrFilterCount, long sectionFilterLength, int filterCaps,
+ @FilterCapabilities int[] filterCapsList, @FilterCapabilities int[] linkCaps,
boolean timeFilter) {
mDemuxCount = demuxCount;
mRecordCount = recordCount;
@@ -71,6 +79,7 @@
mPcrFilterCount = pcrFilterCount;
mSectionFilterLength = sectionFilterLength;
mFilterCaps = filterCaps;
+ mFilterCapsList = filterCapsList;
mLinkCaps = linkCaps;
mSupportTimeFilter = timeFilter;
}
@@ -148,6 +157,24 @@
}
/**
+ * Gets the list of filter main type capabilities in bit field.
+ *
+ * <p>Each element in the returned array represents the supported filter main types
+ * represented as bitwise OR of the types in {@link FilterConfiguration}.
+ * <p>Whereas getFilterCapabilities() returns the bitwise OR value of all the supported filter
+ * types in the system, this API returns a list of supported filter types in the system with
+ * each entry representing the supported filter types per demux resource.
+ *
+ * @return an array of supported filter main types for the demux resources in the system
+ * an empty array should be returned for devices with Tuner HAL version 2 and below
+ */
+ @FilterCapabilities
+ @NonNull
+ public int[] getFilterTypeCapabilityList() {
+ return mFilterCapsList;
+ }
+
+ /**
* Gets link capabilities.
*
* <p>The returned array contains the same elements as the number of types in
diff --git a/media/java/android/media/tv/tuner/DemuxInfo.java b/media/java/android/media/tv/tuner/DemuxInfo.java
new file mode 100644
index 0000000..de76165
--- /dev/null
+++ b/media/java/android/media/tv/tuner/DemuxInfo.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.media.tv.tuner;
+
+import android.annotation.SystemApi;
+import android.media.tv.tuner.DemuxCapabilities.FilterCapabilities;
+
+/**
+ * This class is used to specify information of a demux.
+ *
+ * @hide
+ */
+@SystemApi
+public class DemuxInfo {
+ // Bitwise OR of filter types
+ private int mFilterTypes;
+
+ public DemuxInfo(@FilterCapabilities int filterTypes) {
+ setFilterTypes(filterTypes);
+ }
+
+ /**
+ * Gets the filter types
+ *
+ * @return the filter types
+ */
+ @FilterCapabilities
+ public int getFilterTypes() {
+ return mFilterTypes;
+ }
+
+ /**
+ * Sets the filter types
+ *
+ * @param filterTypes the filter types to set
+ */
+ public void setFilterTypes(@FilterCapabilities int filterTypes) {
+ mFilterTypes = filterTypes;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7039a3e..27c2a98 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -281,6 +281,7 @@
private final TunerResourceManager mTunerResourceManager;
private final int mClientId;
private static int sTunerVersion = TunerVersionChecker.TUNER_VERSION_UNKNOWN;
+ private DemuxInfo mDesiredDemuxInfo = new DemuxInfo(Filter.TYPE_UNDEFINED);
private Frontend mFrontend;
private EventHandler mHandler;
@@ -895,12 +896,7 @@
}
}
- private void releaseAll() {
- // release CiCam before frontend because frontend handle is needed to unlink CiCam
- releaseCiCam();
-
- releaseFrontend();
-
+ private void closeLnb() {
mLnbLock.lock();
try {
// mLnb will be non-null only for owner tuner
@@ -917,8 +913,23 @@
} finally {
mLnbLock.unlock();
}
+ }
+ private void releaseFilters() {
+ synchronized (mFilters) {
+ if (!mFilters.isEmpty()) {
+ for (WeakReference<Filter> weakFilter : mFilters) {
+ Filter filter = weakFilter.get();
+ if (filter != null) {
+ filter.close();
+ }
+ }
+ mFilters.clear();
+ }
+ }
+ }
+ private void releaseDescramblers() {
synchronized (mDescramblers) {
if (!mDescramblers.isEmpty()) {
for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
@@ -931,19 +942,9 @@
mDescramblers.clear();
}
}
+ }
- synchronized (mFilters) {
- if (!mFilters.isEmpty()) {
- for (WeakReference<Filter> weakFilter : mFilters) {
- Filter filter = weakFilter.get();
- if (filter != null) {
- filter.close();
- }
- }
- mFilters.clear();
- }
- }
-
+ private void releaseDemux() {
mDemuxLock.lock();
try {
if (mDemuxHandle != null) {
@@ -957,9 +958,17 @@
} finally {
mDemuxLock.unlock();
}
+ }
+ private void releaseAll() {
+ // release CiCam before frontend because frontend handle is needed to unlink CiCam
+ releaseCiCam();
+ releaseFrontend();
+ closeLnb();
+ releaseDescramblers();
+ releaseFilters();
+ releaseDemux();
mTunerResourceManager.unregisterClientProfile(mClientId);
-
}
/**
@@ -1025,6 +1034,7 @@
private native DvrPlayback nativeOpenDvrPlayback(long bufferSize);
private native DemuxCapabilities nativeGetDemuxCapabilities();
+ private native DemuxInfo nativeGetDemuxInfo(int demuxHandle);
private native int nativeCloseDemux(int handle);
private native int nativeCloseFrontend(int handle);
@@ -1865,6 +1875,30 @@
}
}
+ /**
+ * Gets DemuxInfo of the currently held demux
+ *
+ * @return A {@link DemuxInfo} of currently held demux resource.
+ * Returns null if no demux resource is held.
+ */
+ @Nullable
+ public DemuxInfo getCurrentDemuxInfo() {
+ mDemuxLock.lock();
+ try {
+ if (mDemuxHandle == null) {
+ return null;
+ }
+ return nativeGetDemuxInfo(mDemuxHandle);
+ } finally {
+ mDemuxLock.unlock();
+ }
+ }
+
+ /** @hide */
+ public DemuxInfo getDesiredDemuxInfo() {
+ return mDesiredDemuxInfo;
+ }
+
private void onFrontendEvent(int eventType) {
Log.d(TAG, "Got event from tuning. Event type: " + eventType + " for " + this);
synchronized (mOnTuneEventLock) {
@@ -2173,6 +2207,11 @@
/**
* Opens a filter object based on the given types and buffer size.
*
+ * <p>For TUNER_VERSION_3_0 and above, configureDemuxInternal() will be called with mainType.
+ * However, unlike when configureDemux() is called directly, the desired filter types will not
+ * be changed when previously set desired filter types are the superset of the newly desired
+ * ones.
+ *
* @param mainType the main type of the filter.
* @param subType the subtype of the filter.
* @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the
@@ -2188,6 +2227,15 @@
@Nullable FilterCallback cb) {
mDemuxLock.lock();
try {
+ int tunerMajorVersion = TunerVersionChecker.getMajorVersion(sTunerVersion);
+ if (sTunerVersion >= TunerVersionChecker.TUNER_VERSION_3_0) {
+ DemuxInfo demuxInfo = new DemuxInfo(mainType);
+ int res = configureDemuxInternal(demuxInfo, false /* reduceDesiredFilterTypes */);
+ if (res != RESULT_SUCCESS) {
+ Log.e(TAG, "openFilter called for unsupported mainType: " + mainType);
+ return null;
+ }
+ }
if (!checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, mDemuxLock)) {
return null;
}
@@ -2470,10 +2518,109 @@
return filter;
}
+ /**
+ * Configures the desired {@link DemuxInfo}
+ *
+ * <p>The already held demux and filters will be released when desiredDemuxInfo is null or the
+ * desireDemuxInfo.getFilterTypes() is not supported by the already held demux.
+ *
+ * @param desiredDemuxInfo the desired {@link DemuxInfo}, which includes information such as
+ * filterTypes ({@link DemuxFilterMainType}).
+ * @return result status of configure demux operation. {@link #RESULT_UNAVAILABLE} is returned
+ * when a) the desired capabilities are not supported by the system,
+ * b) this API is called on unsupported version, or
+ * c) either getDemuxCapabilities or getFilterTypeCapabilityList()
+ * returns an empty array
+ */
+ @Result
+ public int configureDemux(@Nullable DemuxInfo desiredDemuxInfo) {
+ int tunerMajorVersion = TunerVersionChecker.getMajorVersion(sTunerVersion);
+ if (sTunerVersion < TunerVersionChecker.TUNER_VERSION_3_0) {
+ Log.e(TAG, "configureDemux() is not supported for tuner version:"
+ + TunerVersionChecker.getMajorVersion(sTunerVersion) + "."
+ + TunerVersionChecker.getMinorVersion(sTunerVersion) + ".");
+ return RESULT_UNAVAILABLE;
+ }
+
+ synchronized (mDemuxLock) {
+ return configureDemuxInternal(desiredDemuxInfo, true /* reduceDesiredFilterTypes */);
+ }
+ }
+
+ private int configureDemuxInternal(@Nullable DemuxInfo desiredDemuxInfo,
+ boolean reduceDesiredFilterTypes) {
+ // release the currently held demux if the desired demux info is null
+ if (desiredDemuxInfo == null) {
+ if (mDemuxHandle != null) {
+ releaseFilters();
+ releaseDemux();
+ }
+ return RESULT_SUCCESS;
+ }
+
+ int desiredFilterTypes = desiredDemuxInfo.getFilterTypes();
+
+ // just update and return success if the desiredFilterTypes is equal to or a subset of
+ // a previously configured value
+ if ((mDesiredDemuxInfo.getFilterTypes() & desiredFilterTypes)
+ == desiredFilterTypes) {
+ if (reduceDesiredFilterTypes) {
+ mDesiredDemuxInfo.setFilterTypes(desiredFilterTypes);
+ }
+ return RESULT_SUCCESS;
+ }
+
+ // check if the desire capability is supported
+ DemuxCapabilities caps = nativeGetDemuxCapabilities();
+ if (caps == null) {
+ Log.e(TAG, "configureDemuxInternal:failed to get DemuxCapabilities");
+ return RESULT_UNAVAILABLE;
+ }
+
+ int[] filterCapsList = caps.getFilterTypeCapabilityList();
+ if (filterCapsList.length <= 0) {
+ Log.e(TAG, "configureDemuxInternal: getFilterTypeCapabilityList()"
+ + " returned an empty array");
+ return RESULT_UNAVAILABLE;
+ }
+
+ boolean supported = false;
+ for (int filterCaps : filterCapsList) {
+ if ((desiredFilterTypes & filterCaps) == desiredFilterTypes) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ Log.e(TAG, "configureDemuxInternal: requested caps:" + desiredFilterTypes
+ + " is not supported by the system");
+ return RESULT_UNAVAILABLE;
+ }
+
+ // close demux if not compatible
+ if (mDemuxHandle != null) {
+ if (desiredFilterTypes != Filter.TYPE_UNDEFINED) {
+ // Release the existing demux only if
+ // the desired caps is not supported
+ DemuxInfo currentDemuxInfo = nativeGetDemuxInfo(mDemuxHandle);
+ if (currentDemuxInfo != null) {
+ if ((desiredFilterTypes & currentDemuxInfo.getFilterTypes())
+ != desiredFilterTypes) {
+ releaseFilters();
+ releaseDemux();
+ }
+ }
+ }
+ }
+ mDesiredDemuxInfo.setFilterTypes(desiredFilterTypes);
+ return RESULT_SUCCESS;
+ }
+
private boolean requestDemux() {
int[] demuxHandle = new int[1];
TunerDemuxRequest request = new TunerDemuxRequest();
request.clientId = mClientId;
+ request.desiredFilterTypes = mDesiredDemuxInfo.getFilterTypes();
boolean granted = mTunerResourceManager.requestDemux(request, demuxHandle);
if (granted) {
mDemuxHandle = demuxHandle[0];
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 15175a7..d268aeb 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -289,6 +289,23 @@
}
/**
+ * Updates the current TRM of the TunerHAL Demux information.
+ *
+ * <p><strong>Note:</strong> This update must happen before the first
+ * {@link #requestDemux(TunerDemuxRequest, int[])} and
+ * {@link #releaseDemux(int, int)} call.
+ *
+ * @param infos an array of the available {@link TunerDemuxInfo} information.
+ */
+ public void setDemuxInfoList(@NonNull TunerDemuxInfo[] infos) {
+ try {
+ mService.setDemuxInfoList(infos);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Updates the TRM of the current CAS information.
*
* <p><strong>Note:</strong> This update must happen before the first
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index e0af76d..5399697 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -20,6 +20,7 @@
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
+import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
@@ -130,6 +131,17 @@
void updateCasInfo(in int casSystemId, in int maxSessionNum);
/*
+ * Updates the available Demux resources information on the current device.
+ *
+ * <p><strong>Note:</strong> This update must happen before the first
+ * {@link #requestDemux(TunerDemux,int[])} and {@link #releaseDemux(int, int)}
+ * call.
+ *
+ * @param infos an array of the available {@link TunerDemux} information.
+ */
+ void setDemuxInfoList(in TunerDemuxInfo[] infos);
+
+ /*
* Updates the available Lnb resource information on the current device.
*
* <p><strong>Note:</strong> This update must happen before the first
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
new file mode 100644
index 0000000..c14caf5
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright 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.media.tv.tunerresourcemanager;
+
+/**
+ * TunerDemuxInfo interface that carries tuner demux information.
+ *
+ * This is used to update the TunerResourceManager demux resources.
+ * @hide
+ */
+parcelable TunerDemuxInfo {
+ /**
+ * Demux handle
+ */
+ int handle;
+
+ /**
+ * Supported filter types (defined in {@link android.media.tv.tuner.filter.Filter})
+ */
+ int filterTypes;
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
index 457f90c..b24e273 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
@@ -23,4 +23,9 @@
*/
parcelable TunerDemuxRequest {
int clientId;
-}
\ No newline at end of file
+
+ /**
+ * Desired filter types (defined in {@link android.media.tv.tuner.filter.Filter})
+ */
+ int desiredFilterTypes;
+}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index aacea3d..a73725b 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -47,6 +47,7 @@
#include <aidl/android/hardware/tv/tuner/DemuxFilterSubType.h>
#include <aidl/android/hardware/tv/tuner/DemuxFilterTemiEvent.h>
#include <aidl/android/hardware/tv/tuner/DemuxFilterTsRecordEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxInfo.h>
#include <aidl/android/hardware/tv/tuner/DemuxIpAddress.h>
#include <aidl/android/hardware/tv/tuner/DemuxIpFilterSettings.h>
#include <aidl/android/hardware/tv/tuner/DemuxIpFilterType.h>
@@ -192,6 +193,7 @@
using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
using ::aidl::android::hardware::tv::tuner::DemuxFilterTemiEvent;
using ::aidl::android::hardware::tv::tuner::DemuxFilterTsRecordEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxInfo;
using ::aidl::android::hardware::tv::tuner::DemuxIpAddress;
using ::aidl::android::hardware::tv::tuner::DemuxIpAddressIpAddress;
using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettings;
@@ -2083,7 +2085,7 @@
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities");
- jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[IZ)V");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[I[IZ)V");
jint numDemux = caps->numDemux;
jint numRecord = caps->numRecord;
@@ -2095,16 +2097,49 @@
jint numPesFilter = caps->numPesFilter;
jint numPcrFilter = caps->numPcrFilter;
jlong numBytesInSectionFilter = caps->numBytesInSectionFilter;
- jint filterCaps = caps->filterCaps;
jboolean bTimeFilter = caps->bTimeFilter;
+ jint filterCaps = caps->filterCaps;
+ jintArray filterCapsList = nullptr;
+ vector<DemuxInfo> demuxInfoList;
+ sTunerClient->getDemuxInfoList(&demuxInfoList);
+ if (demuxInfoList.size() > 0) {
+ vector<int32_t> demuxFilterTypesList;
+ for (int i = 0; i < demuxInfoList.size(); i++) {
+ demuxFilterTypesList.push_back(demuxInfoList[i].filterTypes);
+ }
+ filterCapsList = env->NewIntArray(demuxFilterTypesList.size());
+ env->SetIntArrayRegion(filterCapsList, 0, demuxFilterTypesList.size(),
+ reinterpret_cast<jint *>(&demuxFilterTypesList[0]));
+ } else {
+ filterCapsList = env->NewIntArray(0);
+ }
jintArray linkCaps = env->NewIntArray(caps->linkCaps.size());
env->SetIntArrayRegion(linkCaps, 0, caps->linkCaps.size(),
reinterpret_cast<jint *>(&caps->linkCaps[0]));
return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
- numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter);
+ numBytesInSectionFilter, filterCaps, filterCapsList, linkCaps, bTimeFilter);
+}
+
+jobject JTuner::getDemuxInfo(int handle) {
+ if (sTunerClient == nullptr) {
+ ALOGE("tuner is not initialized");
+ return nullptr;
+ }
+ shared_ptr<DemuxInfo> demuxInfo = sTunerClient->getDemuxInfo(handle);
+ if (demuxInfo == nullptr) {
+ return nullptr;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass clazz = env->FindClass("android/media/tv/tuner/DemuxInfo");
+ jmethodID infoInit = env->GetMethodID(clazz, "<init>", "(I)V");
+
+ jint filterTypes = demuxInfo->filterTypes;
+
+ return env->NewObject(clazz, infoInit, filterTypes);
}
jobject JTuner::getFrontendStatus(jintArray types) {
@@ -4487,6 +4522,11 @@
return tuner->getDemuxCaps();
}
+static jobject android_media_tv_Tuner_get_demux_info(JNIEnv* env, jobject thiz, jint handle) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getDemuxInfo(handle);
+}
+
static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) {
sp<JTuner> tuner = getTuner(env, thiz);
return (jint)tuner->openDemux(handle);
@@ -4878,6 +4918,8 @@
(void *)android_media_tv_Tuner_open_dvr_playback },
{ "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;",
(void *)android_media_tv_Tuner_get_demux_caps },
+ { "nativeGetDemuxInfo", "(I)Landroid/media/tv/tuner/DemuxInfo;",
+ (void *)android_media_tv_Tuner_get_demux_info },
{ "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux },
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner },
{ "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 2b69e89..4069aaf 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -198,6 +198,7 @@
jobject openDescrambler();
jobject openDvr(DvrType type, jlong bufferSize);
jobject getDemuxCaps();
+ jobject getDemuxInfo(int handle);
jobject getFrontendStatus(jintArray types);
Result openDemux(int handle);
jint close();
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index ab28fb4..ea623d9 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -22,7 +22,6 @@
#include "TunerClient.h"
-using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
using ::aidl::android::hardware::tv::tuner::FrontendType;
namespace android {
@@ -108,6 +107,27 @@
return nullptr;
}
+shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int32_t demuxHandle) {
+ if (mTunerService != nullptr) {
+ DemuxInfo aidlDemuxInfo;
+ Status s = mTunerService->getDemuxInfo(demuxHandle, &aidlDemuxInfo);
+ if (!s.isOk()) {
+ return nullptr;
+ }
+ return make_shared<DemuxInfo>(aidlDemuxInfo);
+ }
+ return nullptr;
+}
+
+void TunerClient::getDemuxInfoList(vector<DemuxInfo>* demuxInfoList) {
+ if (mTunerService != nullptr) {
+ Status s = mTunerService->getDemuxInfoList(demuxInfoList);
+ if (!s.isOk()) {
+ demuxInfoList->clear();
+ }
+ }
+}
+
shared_ptr<DemuxCapabilities> TunerClient::getDemuxCaps() {
if (mTunerService != nullptr) {
DemuxCapabilities aidlCaps;
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 3f8b21c..6ab120b 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -31,6 +31,7 @@
using Status = ::ndk::ScopedAStatus;
using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
+using ::aidl::android::hardware::tv::tuner::DemuxInfo;
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
using ::aidl::android::hardware::tv::tuner::FrontendType;
using ::aidl::android::hardware::tv::tuner::Result;
@@ -83,6 +84,21 @@
sp<DemuxClient> openDemux(int32_t demuxHandle);
/**
+ * Retrieve the DemuxInfo of a specific demux
+ *
+ * @param demuxHandle the handle of the demux to query demux info for
+ * @return the demux info
+ */
+ shared_ptr<DemuxInfo> getDemuxInfo(int32_t demuxHandle);
+
+ /**
+ * Retrieve a list of demux info
+ *
+ * @return a list of DemuxInfo
+ */
+ void getDemuxInfoList(vector<DemuxInfo>* demuxInfoList);
+
+ /**
* Retrieve the Demux capabilities.
*
* @return the demux’s capabilities.
diff --git a/media/tests/projection/TEST_MAPPING b/media/tests/projection/TEST_MAPPING
deleted file mode 100644
index ddb68af..0000000
--- a/media/tests/projection/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "android.media.projection.mediaprojectiontests"},
- {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
- }
- ]
-}
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 674168a..6d225c3 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -5,31 +5,25 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Skep op ’n ander plek"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Stoor in ’n ander plek"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Gebruik ’n ander toestel"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Stoor op ’n ander toestel"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Kies waar om <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"skep jou wagwoordsleutels"</string>
- <string name="save_your_password" msgid="6597736507991704307">"stoor jou wagwoord"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"stoor jou aanmeldinligting"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Kies ’n wagwoordbestuurder om jou inligting te stoor en volgende keer vinniger aan te meld."</string>
+ <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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Stoor wagwoord vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Stoor aanmeldinligting vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Jy kan jou <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> op enige toestel gebruik. Dit is in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> gestoor vir <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"wagwoordsleutel"</string>
<string name="password" msgid="6738570945182936667">"wagwoord"</string>
+ <string name="passkeys" msgid="5733880786866559847">"wagwoordsleutels"</string>
+ <string name="passwords" msgid="5419394230391253816">"wagwoorde"</string>
<string name="sign_ins" msgid="4710739369149469208">"aanmeldings"</string>
<string name="sign_in_info" msgid="2627704710674232328">"aanmeldinligting"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Stoor <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> in"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Skep ’n wagwoordsleutel op ’n ander toestel?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Skep wagwoordsleutel op ’n ander toestel?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gebruik <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> vir al jou aanmeldings?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Hierdie wagwoordbestuurder sal jou wagwoorde en wagwoordsleutels berg om jou te help om maklik aan te meld."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Hierdie wagwoordbestuurder sal jou wagwoorde en wagwoordsleutels berg om jou te help om maklik aan te meld"</string>
<string name="set_as_default" msgid="4415328591568654603">"Stel as verstek"</string>
<string name="use_once" msgid="9027366575315399714">"Gebruik een keer"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> wagwoordsleutels"</string>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 2c4f402..8c52cf3 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"በሌላ ቦታ ውስጥ ይፍጠሩ"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ወደ ሌላ ቦታ ያስቀምጡ"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ሌላ መሣሪያ ይጠቀሙ"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ወደ ሌላ መሣሪያ ያስቀምጡ"</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="choose_provider_title" msgid="7245243990139698508">"የት <xliff:g id="CREATETYPES">%1$s</xliff:g> እንደሚሆን ይምረጡ"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"የይለፍ ቁልፎችዎን ይፍጠሩ"</string>
- <string name="save_your_password" msgid="6597736507991704307">"የይለፍ ቃልዎን ያስቀምጡ"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"የመግቢያ መረጃዎን ያስቀምጡ"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"መረጃዎን ለማስቀመጥ እና በሚቀጥለው ጊዜ በፍጥነት ለመግባት የሚስጥር ቁልፍ አስተዳዳሪን ይጠቀሙ።"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"የእርስዎን <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> በማንኛውም መሣሪያ ላይ መጠቀም ይችላሉ። ለ<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ወደ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"በሌላ መሣሪያ የይለፍ ቁልፍ ይፈጠር?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ይህ የይለፍ ቃል አስተዳዳሪ በቀላሉ እንዲገቡ ለማገዝ የእርስዎን የይለፍ ቃሎች እና የይለፍ ቁልፎች ያከማቻል።"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 c0ff69d..6b90817 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"الإنشاء في مكان آخر"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"الحفظ في مكان آخر"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"استخدام جهاز آخر"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"الحفظ على جهاز آخر"</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="choose_provider_title" msgid="7245243990139698508">"اختيار مكان <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"إنشاء مفاتيح مرورك"</string>
- <string name="save_your_password" msgid="6597736507991704307">"حفظ كلمة المرور"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"حفظ معلومات تسجيل الدخول"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"اختَر مدير كلمة مرور لحفظ معلوماتك وتسجيل الدخول بشكل أسرع في المرة القادمة."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"يمكنك استخدام <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> لتطبيق \"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>\" على أي جهاز. يتم حفظه في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\" للحساب \"<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"هل تريد إنشاء مفتاح مرور في جهاز آخر؟"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ستخزِّن خدمة إدارة كلمات المرور هذه كلمات المرور ومفاتيح المرور لمساعدتك في تسجيل الدخول بسهولة."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 2c420fc..3a92b68 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"অন্য ঠাইত সৃষ্টি কৰক"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য ঠাইত ছেভ কৰক"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইচ ব্যৱহাৰ কৰক"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য এটা ডিভাইচত ছেভ কৰক"</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="choose_provider_title" msgid="7245243990139698508">"ক’ত <xliff:g id="CREATETYPES">%1$s</xliff:g> সেয়া বাছনি কৰক"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"আপোনাৰ পাছকী সৃষ্টি কৰক"</string>
- <string name="save_your_password" msgid="6597736507991704307">"আপোনাৰ পাছৱৰ্ড ছেভ কৰক"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"আপোনাৰ ছাইন ইন কৰাৰ তথ্য ছেভ কৰক"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"আপোনাৰ তথ্য ছেভ কৰি পৰৱৰ্তী সময়ত দ্ৰুতভাৱে ছাইন ইন কৰিবলৈ এটা পাছৱৰ্ড পৰিচালক বাছনি কৰক।"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"আপুনি আপোনাৰ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> যিকোনো ডিভাইচত ব্যৱহাৰ কৰিব পাৰে। এইটো <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>ৰ বাবে <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"অন্য এটা ডিভাইচত এটা পাছকী সৃষ্টি কৰিবনে?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"আপোনাক সহজে ছাইন ইন কৰাত সহায় কৰিবলৈ এই পাছৱৰ্ড পৰিচালকটোৱে আপোনাৰ পাছৱৰ্ড আৰু পাছকী ষ্ট’ৰ কৰিব।"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 982562a..d7f3025 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Başqa yerdə yaradın"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Başqa yerdə yadda saxlayın"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Digər cihaz istifadə edin"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Başqa cihazda yadda saxlayın"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> üçün yer seçin"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"giriş açarları yaradın"</string>
- <string name="save_your_password" msgid="6597736507991704307">"parolunuzu yadda saxlayın"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"giriş məlumatınızı yadda saxlayın"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Məlumatlarınızı yadda saxlamaq və növbəti dəfə daha sürətli daxil olmaq üçün parol meneceri seçin."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> domenini istənilən cihazda istifadə edə bilərsiniz. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> xidmətində saxlanılıb."</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Başqa cihazda giriş açarı yaradılsın?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"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>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 2a63a9e..6e8ec71 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Napravi na drugom mestu"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvaj na drugom mestu"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Koristi drugi uređaj"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvaj na drugi uređaj"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite lokaciju za: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"napravite pristupne kodove"</string>
- <string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte podatke o prijavljivanju"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Izaberite menadžera lozinki da biste sačuvali podatke i brže se prijavili sledeći put."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Možete da koristite tip domena <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> na bilo kom uređaju. Čuva se kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za: <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite da napravite pristupni kôd na drugom uređaju?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ovaj menadžer lozinki će čuvati lozinke i pristupne kodove da biste se lako prijavljivali."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 091527a..99af511 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Стварыць у іншым месцы"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Захаваць у іншым месцы"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Скарыстаць іншую прыладу"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Захаваць на іншую прыладу"</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="choose_provider_title" msgid="7245243990139698508">"Выберыце, дзе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"стварыць ключы доступу"</string>
- <string name="save_your_password" msgid="6597736507991704307">"захаваць пароль"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"захаваць інфармацыю пра спосаб уваходу"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Выберыце менеджар пароляў, каб захаваць свае даныя і забяспечыць хуткі ўваход у наступныя разы."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Вы можаце выкарыстоўваць <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g><xliff:g id="APPDOMAINNAME">%1$s</xliff:g> на любой прыладзе. Даныя для \"<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>\" захоўваюцца ў папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"Стварыць ключ доступу на іншай прыладзе?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Каб вам было прасцей уваходзіць у сістэму, вашы паролі і ключы доступу будуць захоўвацца ў менеджары пароляў."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 65ef0df2..13ebe24 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Създаване другаде"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Запазване на друго място"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Използване на друго устройство"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Запазване на друго устройство"</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="choose_provider_title" msgid="7245243990139698508">"Изберете място за <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"създаване на кодовете ви за достъп"</string>
- <string name="save_your_password" msgid="6597736507991704307">"запазване на паролата ви"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"запазване на данните ви за вход"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Изберете мениджър на пароли, в който да се запазят данните ви, така че следващия път да влезете по-бързо в профила си."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Можете да използвате <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> за <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> на всяко устройство. Тези данни се запазват в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"Да се създаде ли код за достъп на друго устройство?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Този мениджър на пароли ще съхранява вашите пароли и кодове за достъп, за да влизате лесно в профила си."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 a6cd1b3..a19fe71 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"অন্য জায়গায় তৈরি করুন"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য জায়গায় সেভ করুন"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইস ব্যবহার করুন"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য ডিভাইসে সেভ করুন"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"আপনার পাসকী তৈরি করা"</string>
- <string name="save_your_password" msgid="6597736507991704307">"আপনার পাসওয়ার্ড সেভ করুন"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"আপনার সাইন-ইন করা সম্পর্কিত তথ্য সেভ করুন"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"আপনার তথ্য সেভ করতে একটি Password Manager বেছে নিন এবং পরের বার আরও ঝটপট সাইন-ইন করুন।"</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>
<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="choose_create_option_description" msgid="5531335144879100664">"যেকোনও ডিভাইসে নিজের <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ব্যবহার করতে পারবেন। এটি <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-এর জন্য <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-এ সেভ করা হয়েছে।"</string>
<string name="passkey" msgid="632353688396759522">"পাসকী"</string>
<string name="password" msgid="6738570945182936667">"পাসওয়ার্ড"</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="6372952459932674632">"অন্য একটি ডিভাইসে পাসকী তৈরি করবেন?"</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="6560593199974037820">"এই Password Manager আপনার পাসওয়ার্ড ও পাসকী সেভ করবে, যাতে সহজেই সাইন-ইন করতে পারেন।"</string>
+ <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-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 3d5db85..6b776f5 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Kreirajte na drugom mjestu"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvajte na drugom mjestu"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Koristite drugi uređaj"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvajte na drugom uređaju"</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="choose_provider_title" msgid="7245243990139698508">"Odaberite gdje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"kreiranje pristupnih ključeva"</string>
- <string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte informacije za prijavu"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Odaberite upravitelja lozinki da sačuvate svoje informacije i brže se prijavite sljedeći put."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Sačuvati lozinku za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Sačuvati informacije o prijavi za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Možete koristiti vrstu akreditiva <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> na bilo kojem uređaju. Sačuvana je na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za račun <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
<string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
+ <string name="passkeys" msgid="5733880786866559847">"pristupni ključevi"</string>
+ <string name="passwords" msgid="5419394230391253816">"lozinke"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informacije o prijavi"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Sačuvajte vrstu akreditiva \"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>\" na"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Kreirati pristupni ključ na drugom uređaju?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Kreirati pristupni ključ na drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Koristiti uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve vaše prijave?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ovaj upravitelj lozinki će pohraniti vaše lozinke i pristupne ključeve da vam olakša prijavu."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Ovaj upravitelj lozinki će pohraniti vaše lozinke i pristupne ključeve da vam olakša prijavu"</string>
<string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
<string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Broj lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 350357a..8943f46 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Crea en un altre lloc"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Desa en un altre lloc"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Utilitza un altre dispositiu"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Desa en un altre dispositiu"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Tria on vols <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crea les teves claus d\'accés"</string>
- <string name="save_your_password" msgid="6597736507991704307">"desar la contrasenya"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"desar la teva informació d\'inici de sessió"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecciona un gestor de contrasenyes per desar la teva informació i iniciar la sessió més ràpidament la pròxima vegada."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Pots utilitzar <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> en qualsevol dispositiu. Està desat a <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> per a <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vols crear una clau d\'accés en un altre dispositiu?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Aquest gestor de contrasenyes emmagatzemarà les teves contrasenyes i claus d\'accés per ajudar-te a iniciar la sessió fàcilment."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 199bce3..06f94d2 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Vytvořit na jiném místě"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Uložit na jiné místo"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Použít jiné zařízení"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Uložit do jiného zařízení"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Zvolte, kde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"vytvářet přístupové klíče"</string>
- <string name="save_your_password" msgid="6597736507991704307">"uložte si heslo"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"uložte své přihlašovací údaje"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Vyberte správce hesel k uložení svých údajů, abyste se příště mohli přihlásit rychleji."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Své identifikační údaje typu <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> pro aplikaci <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> můžete používat na libovolném zařízení. Ukládá se do <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pro uživatele <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vytvořit přístupový klíč v jiném zařízení?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tento správce hesel bude ukládat vaše hesla a přístupové klíče, abyste se mohli snadno přihlásit."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 e8ff4d4..4c68886 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Opret et andet sted"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Gem et andet sted"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Brug en anden enhed"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Gem på en anden enhed"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Vælg, hvor du vil <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"oprette dine adgangsnøgler"</string>
- <string name="save_your_password" msgid="6597736507991704307">"gem din adgangskode"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"gem dine loginoplysninger"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Vælg en adgangskodeadministrator for at gemme dine oplysninger, så du kan logge ind hurtigere næste gang."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Du kan bruge din <xliff:g id="APPDOMAINNAME">%1$s</xliff:g>-<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> på enhver enhed. Den gemmes i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vil du oprette en adgangsnøgle i en anden enhed?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Denne adgangskodeadministrator gemmer dine adgangskoder og adgangsnøgler for at hjælpe dig med nemt at logge ind."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 0d569e4..d26f430 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"An anderem Speicherort erstellen"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"An anderem Ort speichern"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Anderes Gerät verwenden"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Auf einem anderen Gerät speichern"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Ort auswählen für: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"Passkeys erstellen"</string>
- <string name="save_your_password" msgid="6597736507991704307">"Passwort speichern"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"Anmeldedaten speichern"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Du kannst einen Passwortmanager auswählen, um deine Anmeldedaten zu speichern, damit du dich nächstes Mal schneller anmelden kannst."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Du kannst Folgendes von <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> auf jedem beliebigen Gerät verwenden: <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>. Diese Anmeldeoption wird für <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> gespeichert."</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Passkey auf anderem Gerät erstellen?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> für alle Anmeldungen verwenden?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Mit diesem Passwortmanager werden deine Passwörter und Passkeys gespeichert, damit du dich problemlos anmelden kannst."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 d76e1a0..3fb6506 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Δημιουργία σε άλλη θέση"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Αποθήκευση σε άλλη θέση"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Χρήση άλλης συσκευής"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Αποθήκευση σε άλλη συσκευή"</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="choose_provider_title" msgid="7245243990139698508">"Επιλέξτε θέση για <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"δημιουργήστε τα κλειδιά πρόσβασής σας"</string>
- <string name="save_your_password" msgid="6597736507991704307">"αποθήκευση του κωδικού πρόσβασής σας"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"αποθήκευση των στοιχείων σύνδεσής σας"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Επιλέξτε ένα πρόγραμμα διαχείρισης κωδικών πρόσβασης για να αποθηκεύσετε τα στοιχεία σας και να συνδεθείτε πιο γρήγορα την επόμενη φορά."</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="choose_create_option_description" msgid="5531335144879100664">"Μπορείτε να χρησιμοποιήσετε το στοιχείο τύπου <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> του τομέα <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> σε οποιαδήποτε συσκευή. Αποθηκεύτηκε στο <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> για τον χρήστη <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"κλειδί πρόσβασης"</string>
<string name="password" msgid="6738570945182936667">"κωδικός πρόσβασης"</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="6372952459932674632">"Δημιουργία κλειδιού πρόσβασης σε άλλη συσκευή;"</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="6560593199974037820">"Αυτός ο διαχειριστής κωδικών πρόσβασης θα αποθηκεύει τους κωδικούς πρόσβασης και τα κλειδιά πρόσβασης, για να συνδέεστε εύκολα."</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-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 5315d32..0bccea1 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</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="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
- <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Select a password manager to save your info and sign in faster next time."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"passwords"</string>
<string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sign-in info"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Save <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> to"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Create passkey on another device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"This password manager will store your passwords and passkeys to help you easily sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
<string name="use_once" msgid="9027366575315399714">"Use once"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index 7917d0a..38637df 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</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="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
- <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Select a password manager to save your info and sign in faster next time."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"passwords"</string>
<string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sign-in info"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Save <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> to"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Create passkey in another device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"This password manager will store your passwords and passkeys to help you easily sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
<string name="use_once" msgid="9027366575315399714">"Use once"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 5315d32..0bccea1 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</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="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
- <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Select a password manager to save your info and sign in faster next time."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"passwords"</string>
<string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sign-in info"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Save <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> to"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Create passkey on another device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"This password manager will store your passwords and passkeys to help you easily sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
<string name="use_once" msgid="9027366575315399714">"Use once"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 5315d32..0bccea1 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</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="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
- <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Select a password manager to save your info and sign in faster next time."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"passwords"</string>
<string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sign-in info"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Save <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> to"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Create passkey on another device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"This password manager will store your passwords and passkeys to help you easily sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
<string name="use_once" msgid="9027366575315399714">"Use once"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index 357efc1..081cfe8 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</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="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
- <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Select a password manager to save your info and sign in faster next time."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
+ <string name="passwords" msgid="5419394230391253816">"passwords"</string>
<string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"sign-in info"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Save <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> to"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Create passkey in another device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"This password manager will store your passwords and passkeys to help you easily sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
<string name="use_once" msgid="9027366575315399714">"Use once"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index acc9240a..9a6c3f3 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear en otra ubicación"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otra ubicación"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crea tus llaves de acceso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de acceso"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecciona un administrador de contraseñas para guardar la información y acceder más rápido la próxima vez."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Puedes usar tu <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> en cualquier dispositivo. Se guardó en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"¿Quieres crear una llave de acceso en otro dispositivo?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Quieres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus accesos?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este administrador de contraseñas almacenará tus contraseñas y llaves de acceso para ayudarte a acceder fácilmente."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 034a9ca..73f6e2f 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear en otro lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otro lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crea tus llaves de acceso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de inicio de sesión"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecciona un gestor de contraseñas para guardar tu información e iniciar sesión más rápido la próxima vez."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Puedes usar tu <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> de <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> en cualquier dispositivo. Se guarda en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"¿Crear una llave de acceso en otro dispositivo?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gestor de contraseñas almacenará tus contraseñas y llaves de acceso para que puedas iniciar sesión fácilmente."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7277674..597ad7f 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Loo teises kohas"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvesta teise kohta"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Kasuta teist seadet"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvesta teise seadmesse"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Valige, kus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"looge oma pääsuvõtmed"</string>
- <string name="save_your_password" msgid="6597736507991704307">"parool salvestada"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"sisselogimisandmed salvestada"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Valige paroolihaldur, et salvestada oma teave ja järgmisel korral kiiremini sisse logida."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Saate üksust <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> kasutada mis tahes seadmes. See salvestatakse teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> kasutaja <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> jaoks"</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Kas luua pääsuvõti teises seadmes?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"See paroolihaldur salvestab teie paroolid ja pääsuvõtmed, et aidata teil hõlpsalt sisse logida."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 a0e1f38..0178141 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Sortu beste toki batean"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Gorde beste toki batean"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Erabili beste gailu bat"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Gorde beste gailu batean"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Aukeratu non <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"sortu sarbide-gakoak"</string>
- <string name="save_your_password" msgid="6597736507991704307">"gorde pasahitza"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"gorde kredentzialei buruzko informazioa"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Hautatu informazioa gordetzeko pasahitz-kudeatzaile bat eta hasi saioa bizkorrago hurrengoan."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> aplikazioko <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> gailu guztietan erabil dezakezu. <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> aplikazioan dago gordeta (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)."</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Sarbide-gako bat sortu nahi duzu beste gailu batean?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> erabili nahi duzu kredentzial guztietarako?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pasahitz-kudeatzaile honek pasahitzak eta sarbide-gakoak gordeko ditu saioa erraz has dezazun."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 18099c9..1b11819 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"ایجاد در مکانی دیگر"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ذخیره در مکانی دیگر"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"استفاده از دستگاهی دیگر"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ذخیره در دستگاهی دیگر"</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="choose_provider_title" msgid="7245243990139698508">"انتخاب محل <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ایجاد گذرکلید"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ذخیره گذرواژه"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ذخیره اطلاعات ورود به سیستم"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"مدیر گذرواژهای انتخاب کنید تا اطلاعاتتان ذخیره شود و دفعه بعدی سریعتر به سیستم وارد شوید."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"میتوانید از <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> در هر دستگاهی استفاده کنید. این مورد در <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> برای <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"گذرکلید در دستگاهی دیگر ایجاد شود؟"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"این مدیر گذرواژه گذرکلیدها و گذرواژههای شما را ذخیره خواهد کرد تا بهراحتی بتوانید به سیستم وارد شوید."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 ef7adc0..bdb55fb 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Luo muualla"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Tallenna muualle"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Käytä toista laitetta"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Tallenna toiselle laitteelle"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Valitse paikka: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"luo avainkoodeja"</string>
- <string name="save_your_password" msgid="6597736507991704307">"tallenna salasanasi"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"tallenna kirjautumistiedot"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Valitse salasanojen ylläpito-ohjelma, niin voit tallentaa tietosi ja kirjautua ensi kerralla nopeammin sisään."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> (<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>) on käytettävissä millä tahansa laitteella. Se tallennetaan tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Luodaanko avainkoodi toisella laitteella?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tämä salasanojen ylläpitotyökalu tallentaa salasanat ja avainkoodit, jotta voit kirjautua helposti sisään."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 25b907d..1e4b009 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Créer à un autre emplacement"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer à un autre emplacement"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"créer vos clés d\'accès"</string>
- <string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos données de connexion"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos renseignements et vous connecter plus rapidement la prochaine fois."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Vous pouvez utiliser votre <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> sur n\'importe quel appareil. Il est enregistré sur <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pour <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Créer une clé d\'accès dans un autre appareil?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ce gestionnaire de mots de passe va enregistrer vos mots de passe et vos clés d\'accès pour vous aider à vous connecter facilement."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 fe5d894..7073ca6 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Créer ailleurs"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer ailleurs"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"créer vos clés d\'accès"</string>
- <string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos informations de connexion"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos informations et vous connecter plus rapidement la prochaine fois."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Vous pouvez utiliser votre <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> sur n\'importe quel appareil. Elle est enregistrée dans le <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> de <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Créer une clé d\'accès dans un autre appareil ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions ?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"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>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 d6b56f7..5b6e719 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear noutro lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Gardar noutro lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Gardar noutro dispositivo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolle onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crear as túas claves de acceso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"gardar o contrasinal"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"gardar a información de inicio de sesión"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"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>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Podes usar a túa <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> de <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> en calquera dispositivo. Gárdase en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Queres crear unha clave de acceso noutro dispositivo?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este xestor de contrasinais almacenará os contrasinais e as claves de acceso para axudarche a iniciar sesión facilmente."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 e497663..fdaf586 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"કોઈ અન્ય સ્થાન પર બનાવો"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"કોઈ અન્ય સ્થાન પર સાચવો"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"અન્ય ડિવાઇસ પર સાચવો"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી છે, તે પસંદ કરો"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"તમારી પાસકી બનાવો"</string>
- <string name="save_your_password" msgid="6597736507991704307">"તમારો પાસવર્ડ સાચવો"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"તમારી સાઇન-ઇનની માહિતી સાચવો"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"તમારી માહિતી સાચવવા માટે પાસવર્ડ મેનેજર પસંદ કરો અને આગલી વખતે વધુ ઝડપથી સાઇન ઇન કરો."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"તમે કોઈપણ ડિવાઇસ પર તમારા <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>નો ઉપયોગ કરી શકો છો. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> માટે <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"શું અન્ય ડિવાઇસમાં પાસકી બનાવવા માગો છો?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"આ પાસવર્ડ મેનેજર તમને સરળતાથી સાઇન ઇન કરવામાં સહાય કરવા માટે, તમારા પાસવર્ડ અને પાસકીને સ્ટોર કરશે."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 c0d53a0..f75a989 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"दूसरी जगह पर बनाएं"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"दूसरी जगह पर सेव करें"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"दूसरे डिवाइस का इस्तेमाल करें"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"दूसरे डिवाइस पर सेव करें"</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="choose_provider_title" msgid="7245243990139698508">"चुनें कि <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां पर सेव करना है"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"अपनी पासकी बनाएं"</string>
- <string name="save_your_password" msgid="6597736507991704307">"अपना पासवर्ड सेव करें"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"साइन इन से जुड़ी अपनी जानकारी सेव करें"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"अपनी जानकारी सेव करने के लिए, कोई पासवर्ड मैनेजर चुनें और अगली बार तेज़ी से साइन इन करें."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"अपने <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> को किसी भी डिवाइस पर इस्तेमाल किया जा सकता है. इसे <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> के लिए, <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"क्या आपको किसी दूसरे डिवाइस में पासकी बनानी है?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"पासवर्ड और पासकी को इस पासवर्ड मैनेजर में सेव करके, आसानी से साइन इन किया जा सकता है."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 0a171cc..2f9e46b 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Izradi na drugom mjestu"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Spremi na drugom mjestu"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Upotrijebite neki drugi uređaj"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Spremi na drugi uređaj"</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="choose_provider_title" msgid="7245243990139698508">"Odaberite mjesto za sljedeće: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"izradite pristupne ključeve"</string>
- <string name="save_your_password" msgid="6597736507991704307">"spremi zaporku"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"spremi podatke za prijavu"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Odaberite upravitelja zaporki kako biste spremili svoje informacije i drugi se put brže prijavili."</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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Spremiti zaporku za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Spremiti informacije o prijavi za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Aplikaciju <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> možete upotrijebiti na bilo kojem uređaju. Sprema se na uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
<string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
<string name="password" msgid="6738570945182936667">"zaporka"</string>
+ <string name="passkeys" msgid="5733880786866559847">"pristupni ključevi"</string>
+ <string name="passwords" msgid="5419394230391253816">"zaporke"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informacije o prijavi"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Spremi <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> u"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite li izraditi pristupni ključ na nekom drugom uređaju?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Želite li izraditi pristupni ključ na drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite li upotrebljavati uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve prijave?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Upravitelj zaporki pohranit će vaše zaporke i pristupne ključeve radi jednostavnije prijave."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Upravitelj zaporki pohranit će vaše zaporke i pristupne ključeve radi jednostavnije prijave"</string>
<string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
<string name="use_once" msgid="9027366575315399714">"Upotrijebi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Broj zaporki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 6a7531a..81616df 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Létrehozás másik helyen"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Mentés másik helyre"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Másik eszköz használata"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Mentés másik eszközre"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Válassza ki a(z) <xliff:g id="CREATETYPES">%1$s</xliff:g> helyét"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"azonosítókulcsok létrehozása"</string>
- <string name="save_your_password" msgid="6597736507991704307">"jelszó mentése"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"bejelentkezési adatok mentése"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Jelszókezelő kiválasztásával mentheti a saját adatokat, és gyorsabban jelentkezhet be a következő alkalommal."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"A(z) <xliff:g id="APPDOMAINNAME">%1$s</xliff:g>-<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> bármilyen eszközön használható. A(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> szolgáltatásba van mentve a következő számára: <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Létrehoz azonosítókulcsot egy másik eszközön?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ez a jelszókezelő a bejelentkezés megkönnyítése érdekében tárolja jelszavait és azonosítókulcsait."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 d5d1217..782b2d9 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Ստեղծել այլ տեղում"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Պահել այլ տեղում"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Օգտագործել այլ սարք"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Պահել մեկ այլ սարքում"</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="choose_provider_title" msgid="7245243990139698508">"Ընտրեք, թե որտեղ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ստեղծել ձեր անցաբառերը"</string>
- <string name="save_your_password" msgid="6597736507991704307">"պահել գաղտնաբառը"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"պահել մուտքի տվյալները"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Ընտրեք գաղտնաբառերի կառավարիչ՝ ձեր տեղեկությունները պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար։"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Դուք կարող եք «<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>» հավելվածի ձեր <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>ն օգտագործել ցանկացած սարքում։ Այն պահված է «<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>» հավելվածում <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"Ստեղծե՞լ անցաբառ մեկ այլ սարքում"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Գաղտնաբառերի այս կառավարիչը կպահի ձեր գաղտնաբառերն ու անցաբառերը՝ օգնելու ձեզ հեշտությամբ մուտք գործել հաշիվ։"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 69f2177..f16a321 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Buat di tempat lain"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan ke tempat lain"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Gunakan perangkat lain"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan ke perangkat lain"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"membuat kunci sandi Anda"</string>
- <string name="save_your_password" msgid="6597736507991704307">"menyimpan sandi Anda"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"menyimpan info login Anda"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Pilih pengelola sandi untuk menyimpan info Anda dan login lebih cepat pada waktu berikutnya."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Anda dapat menggunakan <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> di perangkat mana pun. Disimpan ke <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> untuk <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Buat kunci sandi di perangkat lain?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua info login Anda?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pengelola sandi ini akan menyimpan sandi dan kunci sandi untuk membantu Anda login dengan mudah."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 fc0ca94..170cd9a 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Búa til annarsstaðar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Vista annarsstaðar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Nota annað tæki"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Vista í öðru tæki"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Veldu hvar á að <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"búa til aðgangslykla"</string>
- <string name="save_your_password" msgid="6597736507991704307">"vistaðu aðgangsorðið"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"vistaðu innskráningarupplýsingarnar"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Veldu aðgangsorðastjórnun til að vista upplýsingarnar og vera fljótari að skrá þig inn næst."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Þú getur notað <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> í hvaða tæki sem er. Það er vistað á <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> fyrir <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Viltu búa til aðgangslykil í öðru tæki?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Nota <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> fyrir allar innskráningar?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Þessi aðgangsorðastjórnun vistar aðgangsorð og aðgangslykla til að auðvelda þér að skrá þig inn."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 00489f5..0707256 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Crea in un altro luogo"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Salva in un altro luogo"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usa un altro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Salva su un altro dispositivo"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Scegli dove <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"Crea le tue passkey"</string>
- <string name="save_your_password" msgid="6597736507991704307">"salva la password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"salva le tue informazioni di accesso"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Seleziona un gestore delle password per salvare i tuoi dati e accedere più velocemente la prossima volta."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Puoi usare la tua <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> su qualsiasi dispositivo. Questa credenziale viene salvata in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> per <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vuoi creare una passkey su un altro dispositivo?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vuoi usare <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per tutti gli accessi?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Questo gestore delle password archivierà le password e le passkey per aiutarti ad accedere facilmente."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 c5201b1..be1af3b 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"יצירה במקום אחר"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"שמירה במקום אחר"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"שימוש במכשיר אחר"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"שמירה במכשיר אחר"</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="choose_provider_title" msgid="7245243990139698508">"צריך לבחור לאן <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"יצירת מפתחות גישה"</string>
- <string name="save_your_password" msgid="6597736507991704307">"שמירת הסיסמה שלך"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"שמירת פרטי הכניסה שלך"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"אפשר לבחור באחד משירותי ניהול הסיסמאות כדי לשמור את הפרטים ולהיכנס לחשבון מהר יותר בפעם הבאה."</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="choose_create_option_description" msgid="5531335144879100664">"אפשר להשתמש ב<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> של <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> בכל מכשיר. הוא שמור ב<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> של <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"מפתח גישה"</string>
<string name="password" msgid="6738570945182936667">"סיסמה"</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="6372952459932674632">"ליצור מפתח גישה במכשיר אחר?"</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="6560593199974037820">"במנהל הסיסמאות הזה יאוחסנו הסיסמאות ומפתחות הגישה שלך, כדי לעזור לך להיכנס לחשבון בקלות."</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-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index 18681fe..9bdb9b0 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"別の場所で作成"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"別の場所に保存"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"別のデバイスを使用"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"他のデバイスに保存"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> の保存場所の選択"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"パスキーの作成"</string>
- <string name="save_your_password" msgid="6597736507991704307">"パスワードを保存"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ログイン情報を保存"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"パスワード マネージャーを選択して情報を保存しておくと、次回からすばやくログインできます。"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> の<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>はどのデバイスでも使用できます。<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> の <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"他のデバイスでパスキーを作成しますか?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"このパスワード マネージャーに、パスワードやパスキーが保存され、簡単にログインできるようになります。"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 72f6d19..5b8398a 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"სხვა სივრცეში შექმნა"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"სხვა სივრცეში შენახვა"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"სხვა მოწყობილობის გამოყენება"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"სხვა მოწყობილობაზე შენახვა"</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="choose_provider_title" msgid="7245243990139698508">"აირჩიეთ, სად უნდა <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"შექმენით თქვენი პაროლი"</string>
- <string name="save_your_password" msgid="6597736507991704307">"შეინახეთ თქვენი პაროლი"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"შეინახეთ თქვენი სისტემაში შესვლის ინფორმაცია"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"აირჩიეთ პაროლების მმართველი თქვენი ინფორმაციის შესანახად, რომ მომავალში უფრო სწრაფად შეხვიდეთ."</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="choose_create_option_description" msgid="5531335144879100664">"შეგიძლიათ გამოიყენოთ თქვენი <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ნებისმიერ მოწყობილობაზე. ის შეინახება <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-ზე <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-თვის."</string>
<string name="passkey" msgid="632353688396759522">"წვდომის გასაღები"</string>
<string name="password" msgid="6738570945182936667">"პაროლი"</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="6372952459932674632">"გსურთ პაროლის შექმნა სხვა მოწყობილობაში?"</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="6560593199974037820">"მოცემული პაროლების მმართველი შეინახავს თქვენს პაროლებს და წვდომის გასაღებს, რომლებიც დაგეხმარებათ სისტემაში მარტივად შესვლაში."</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-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index 5d1bb93..bf58b21 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Басқа орында жасау"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Басқа орынға сақтау"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Басқа құрылғыны пайдалану"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Басқа құрылғыға сақтау"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> таңдау"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"кіру кілттерін жасаңыз"</string>
- <string name="save_your_password" msgid="6597736507991704307">"құпия сөзді сақтау"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"тіркелу деректерін сақтау"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Мәліметіңізді сақтап, келесіде жылдам кіру үшін құпия сөз менеджерін таңдаңыз."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> кез келген құрылғыда пайдаланыла алады. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> үшін ол <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"Кіру кілті басқа құрылғыда жасалсын ба?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Аккаунтқа оңай кіру үшін құпия сөз менеджері құпия сөздер мен кіру кілттерін сақтайды."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 1edc795..1966aa1 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"បង្កើតនៅកន្លែងផ្សេងទៀត"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"រក្សាទុកក្នុងកន្លែងផ្សេងទៀត"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ប្រើឧបករណ៍ផ្សេងទៀត"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"រក្សាទុកទៅក្នុងឧបករណ៍ផ្សេង"</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="choose_provider_title" msgid="7245243990139698508">"ជ្រើសរើសកន្លែងដែលត្រូវ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"បង្កើតកូដសម្ងាត់របស់អ្នក"</string>
- <string name="save_your_password" msgid="6597736507991704307">"រក្សាទុកពាក្យសម្ងាត់របស់អ្នក"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"រក្សាទុកព័ត៌មានចូលគណនីរបស់អ្នក"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ជ្រើសរើសកម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ ដើម្បីរក្សាទុកព័ត៌មានរបស់អ្នក និងចូលគណនីបានលឿនជាងមុនលើកក្រោយ។"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"អ្នកអាចប្រើ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> របស់អ្នកនៅលើឧបករណ៍ណាក៏បាន។ វាត្រូវបានរក្សាទុកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> សម្រាប់ <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"បង្កើតកូដសម្ងាត់នៅក្នុងឧបករណ៍ផ្សេងទៀតឬ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់នេះនឹងរក្សាទុកពាក្យសម្ងាត់ និងកូដសម្ងាត់របស់អ្នក ដើម្បីជួយឱ្យអ្នកចូលគណនីបានយ៉ាងងាយស្រួល។"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 cac0a67..cfc1098 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"ಮತ್ತೊಂದು ಸ್ಥಳದಲ್ಲಿ ರಚಿಸಿ"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ಮತ್ತೊಂದು ಸ್ಥಳದಲ್ಲಿ ಉಳಿಸಿ"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ಬೇರೊಂದು ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ಬೇರೊಂದು ಸಾಧನದಲ್ಲಿ ಉಳಿಸಿ"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ನಿಮ್ಮ ಪಾಸ್ಕೀಗಳನ್ನು ರಚಿಸಿ"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಉಳಿಸಿ"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಮಾಹಿತಿ ಉಳಿಸಿ"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಉಳಿಸಲು ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ ಹಾಗೂ ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡಿ."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"ನೀವು ಯಾವುದೇ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ಅನ್ನು ಬಳಸಬಹುದು. ಇದನ್ನು <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"ಮತ್ತೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್ಕೀ ರಚಿಸಬೇಕೆ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ಈ ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕವು ನಿಮಗೆ ಸುಲಭವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಪಾಸ್ಕೀಗಳನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 0902797..ed53a6c 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"다른 위치에 만들기"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"다른 위치에 저장"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"다른 기기 사용"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"다른 기기에 저장"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 작업을 위한 위치 선택"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"패스키 만들기"</string>
- <string name="save_your_password" msgid="6597736507991704307">"비밀번호 저장"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"로그인 정보 저장"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"정보를 저장해서 다음에 더 빠르게 로그인하려면 비밀번호 관리자를 선택하세요."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"기기에서 <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>을(를) 사용할 수 있습니다. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>을(를) 위해 <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"다른 기기에서 패스키를 만들까요?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"이 비밀번호 관리자는 비밀번호와 패스키를 저장하여 사용자가 간편하게 로그인하도록 돕습니다."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 5bc4924..68ce3c7 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Башка жерде түзүү"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Башка жерге сактоо"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Башка түзмөк колдонуу"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Башка түзмөккө сактоо"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> үчүн жер тандаңыз"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"мүмкүндүк алуу ачкычтарын түзүү"</string>
- <string name="save_your_password" msgid="6597736507991704307">"сырсөзүңүздү сактаңыз"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"кирүү маалыматын сактаңыз"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Маалыматыңызды сактоо жана кийинки жолу тезирээк кирүү үчүн сырсөздөрдү башкаргычты тандаңыз."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> каалаган түзмөктө колдонулат. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> маалыматы <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"Мүмкүндүк алуу ачкычы башка түзмөктө түзүлсүнбү?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Сырсөздөрүңүздү жана ачкычтарыңызды Сырсөздөрдү башкаргычка сактап коюп, каалаган убакта колдоно берсеңиз болот."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 72968ea..9814521 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"ສ້າງໃນບ່ອນອື່ນ"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ບັນທຶກໃສ່ບ່ອນອື່ນ"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ໃຊ້ອຸປະກອນອື່ນ"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ບັນທຶກໃສ່ອຸປະກອນອື່ນ"</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="choose_provider_title" msgid="7245243990139698508">"ເລືອກບ່ອນທີ່ຈະ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ສ້າງກະແຈຜ່ານຂອງທ່ານ"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ບັນທຶກລະຫັດຜ່ານຂອງທ່ານ"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບຂອງທ່ານ"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ເລືອກຕົວຈັດການລະຫັດຜ່ານເພື່ອບັນທຶກຂໍ້ມູນຂອງທ່ານ ແລະ ເຂົ້າສູ່ລະບົບໄວຂຶ້ນໃນເທື່ອຕໍ່ໄປ."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"ທ່ານສາມາດໃຊ້ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ຂອງທ່ານຢູ່ອຸປະກອນໃດກໍໄດ້. ມັນຈະຖືກບັນທຶກໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ສຳລັບ <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"ສ້າງກະແຈຜ່ານໃນອຸປະກອນອື່ນບໍ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ຕົວຈັດການລະຫັດຜ່ານນີ້ຈະຈັດເກັບລະຫັດຜ່ານ ແລະ ກະແຈຜ່ານຂອງທ່ານໄວ້ເພື່ອຊ່ວຍໃຫ້ທ່ານເຂົ້າສູ່ລະບົບໄດ້ໂດຍງ່າຍ."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 bcebd79..5ec68bb 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Sukurti kitoje vietoje"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Išsaugoti kitoje vietoje"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Naudoti kitą įrenginį"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Išsaugoti kitame įrenginyje"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pasirinkite, kur <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"kurkite slaptažodžius"</string>
- <string name="save_your_password" msgid="6597736507991704307">"išsaugoti slaptažodį"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"išsaugoti prisijungimo informaciją"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Pasirinkite slaptažodžių tvarkyklę, kurią naudodami galėsite išsaugoti informaciją ir kitą kartą prisijungti greičiau."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Galite naudoti „<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>“ <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> bet kuriame įrenginyje. Jis išsaugomas šioje sistemoje: <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)"</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Sukurti slaptažodį kitame įrenginyje?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> visada prisijungiant?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Šioje slaptažodžių tvarkyklėje bus saugomi jūsų slaptažodžiai, kad galėtumėte lengvai prisijungti."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 b0ffe40..71ab864 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Izveidot citur"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Saglabāt citur"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Izmantot citu ierīci"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Saglabāt citā ierīcē"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Izvēlieties, kur: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"veidot piekļuves atslēgas"</string>
- <string name="save_your_password" msgid="6597736507991704307">"saglabāt paroli"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"saglabāt pierakstīšanās informāciju"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Lai saglabātu informāciju un nākamreiz varētu pierakstīties ātrāk, atlasiet paroļu pārvaldnieku."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> — to varat izmantot jebkurā ierīcē. Šī informācija tiek saglabāta pakalpojumā <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ar kontu <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vai izveidot piekļuves atslēgu citā ierīcē?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Šis paroļu pārvaldnieks glabās jūsu paroles un piekļuves atslēgas, lai atvieglotu pierakstīšanos."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 ea9750b8..ae7473f 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Создајте на друго место"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Зачувајте на друго место"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Употребете друг уред"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Зачувајте на друг уред"</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="choose_provider_title" msgid="7245243990139698508">"Изберете каде да <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"создајте криптографски клучеви"</string>
- <string name="save_your_password" msgid="6597736507991704307">"се зачува лозинката"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"се зачуваат податоците за најавување"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Изберете управник со лозинки за да ги зачувате податоците и да се најавите побрзо следниот пат."</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>
<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="choose_create_option_description" msgid="5531335144879100664">"Може да го користите вашиот <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> за <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> на секој уред. Зачуван е во <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"криптографски клуч"</string>
<string name="password" msgid="6738570945182936667">"лозинка"</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="6372952459932674632">"Да се создаде криптографски клуч во друг уред?"</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="6560593199974037820">"Овој управник со лозинки ќе ги складира вашите лозинки и криптографски клучеви за да ви помогне лесно да се најавите."</string>
+ <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-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index 37c02a9..4075e69 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"മറ്റൊരു സ്ഥലത്ത് സൃഷ്ടിക്കുക"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"മറ്റൊരു സ്ഥലത്തേക്ക് സംരക്ഷിക്കുക"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"മറ്റൊരു ഉപകരണത്തിലേക്ക് സംരക്ഷിക്കുക"</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="choose_provider_title" msgid="7245243990139698508">"എവിടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എന്ന് തിരഞ്ഞെടുക്കുക"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"നിങ്ങളുടെ പാസ്കീകൾ സൃഷ്ടിക്കുക"</string>
- <string name="save_your_password" msgid="6597736507991704307">"നിങ്ങളുടെ പാസ്വേഡ് സംരക്ഷിക്കുക"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"നിങ്ങളുടെ സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കുക"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"നിങ്ങളുടെ വിവരങ്ങൾ സംരക്ഷിക്കാനും അടുത്ത തവണ വേഗത്തിൽ സൈൻ ഇൻ ചെയ്യാനും ഒരു പാസ്വേഡ് മാനേജർ തിരഞ്ഞെടുക്കുക."</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="choose_create_option_description" msgid="5531335144879100664">"നിങ്ങളുടെ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ഏത് ഉപകരണത്തിലും നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഇത് <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> എന്ന വിലാസത്തിനായി <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിച്ചു."</string>
<string name="passkey" msgid="632353688396759522">"പാസ്കീ"</string>
<string name="password" msgid="6738570945182936667">"പാസ്വേഡ്"</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="6372952459932674632">"മറ്റൊരു ഉപകരണത്തിൽ പാസ്കീ സൃഷ്ടിക്കണോ?"</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="6560593199974037820">"എളുപ്പത്തിൽ സൈൻ ഇൻ ചെയ്യാൻ സഹായിക്കുന്നതിന് ഈ പാസ്വേഡ് മാനേജർ നിങ്ങളുടെ പാസ്വേഡുകളും പാസ്കീകളും സംഭരിക്കും."</string>
+ <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-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index 5817ce7..0ac9ce8 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Өөр газар үүсгэх"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Өөр газар хадгалах"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Өөр төхөөрөмж ашиглах"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Өөр төхөөрөмжид хадгалах"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Хаана <xliff:g id="CREATETYPES">%1$s</xliff:g>-г сонгоно уу"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"passkey-үүдээ үүсгэнэ үү"</string>
- <string name="save_your_password" msgid="6597736507991704307">"нууц үгээ хадгалах"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"нэвтрэх мэдээллээ хадгалах"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Мэдээллээ хадгалахын тулд нууц үгний менежер сонгож, дараагийн удаа илүү хурдан нэвтрээрэй."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Та өөрийн <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>-г дурын төхөөрөмжид ашиглах боломжтой. Үүнийг <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-д <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"Өөр төхөөрөмжид passkey үүсгэх үү?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Танд хялбархан нэвтрэхэд туслахын тулд энэ нууц үгний менежер таны нууц үг болон passkey-г хадгална."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 0b4b55e..ab69307 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"दुसऱ्या ठिकाणी तयार करा"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"दुसऱ्या ठिकाणी सेव्ह करा"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"दुसरे डिव्हाइस वापरा"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"दुसऱ्या डिव्हाइसवर सेव्ह करा"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे करायचे ते निवडा"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"तुमच्या पासकी तयार करा"</string>
- <string name="save_your_password" msgid="6597736507991704307">"तुमचा पासवर्ड सेव्ह करा"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"तुमची साइन-इन माहिती सेव्ह करा"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"तुमची माहिती सेव्ह करण्यासाठी आणि पुढच्या वेळी जलद साइन इन करण्याकरिता Password Manager निवडा."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"तुम्ही कोणत्याही डिव्हाइसवर तुमचे <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> वापरू शकता. ते <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> साठी <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"दुसऱ्या डिव्हाइसमध्ये पासकी तयार करायची आहे का?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"तुम्हाला सहजरीत्या साइन इन करण्यात मदत करण्यासाठी हा पासवर्ड व्यवस्थापक तुमचे पासवर्ड आणि पासकी स्टोअर करेल."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 c6d7e09..d95c3ea 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Buat di tempat lain"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan di tempat lain"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Gunakan peranti lain"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan kepada peranti lain"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"buat kunci laluan anda"</string>
- <string name="save_your_password" msgid="6597736507991704307">"simpan kata laluan anda"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"simpan maklumat log masuk anda"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Pilih password manager untuk menyimpan maklumat anda dan log masuk lebih pantas pada kali seterusnya."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Anda boleh menggunakan <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> anda pada mana-mana peranti. Ia disimpan pada <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> untuk <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Buat kunci laluan dalam peranti lain?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua log masuk anda?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pengurus kata laluan ini akan menyimpan kata laluan dan kunci laluan anda untuk membantu anda log masuk dengan mudah."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 4237b00..6630ffa 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"နောက်တစ်နေရာတွင် ပြုလုပ်ရန်"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"နောက်တစ်နေရာတွင် သိမ်းရန်"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"စက်နောက်တစ်ခု သုံးရန်"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"စက်နောက်တစ်ခုတွင် သိမ်းရန်"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ရန် နေရာရွေးပါ"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"သင့်လျှို့ဝှက်ကီး ပြုလုပ်ခြင်း"</string>
- <string name="save_your_password" msgid="6597736507991704307">"သင့်စကားဝှက် သိမ်းရန်"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"သင်၏ လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို သိမ်းရန်"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"သင်၏အချက်အလက်ကို သိမ်းပြီး နောက်တစ်ကြိမ်၌ ပိုမိုမြန်ဆန်စွာ လက်မှတ်ထိုးဝင်ရန် စကားဝှက်မန်နေဂျာကို ရွေးပါ။"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"မည်သည့်စက်တွင်မဆို သင်၏ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ကို သုံးနိုင်သည်။ ၎င်းကို <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> အတွက် <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"အခြားစက်တွင် လျှို့ဝှက်ကီးပြုလုပ်မလား။"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"သင်အလွယ်တကူ လက်မှတ်ထိုးဝင်နိုင်ရန် ဤစကားဝှက်မန်နေဂျာက စကားဝှက်နှင့် လျှို့ဝှက်ကီးများကို သိမ်းပါမည်။"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 91593d3..34a81e8 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Opprett på et annet sted"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Lagre på et annet sted"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Bruk en annen enhet"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Lagre på en annen enhet"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Velg hvor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"opprette tilgangsnøklene dine"</string>
- <string name="save_your_password" msgid="6597736507991704307">"lagre passordet ditt"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"lagre påloggingsinformasjonen din"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Velg et verktøy for passordlagring for å lagre informasjonen din og logge på raskere neste gang."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Du kan bruke <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>-elementet for <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> på alle slags enheter. Det lagres i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vil du opprette en tilgangsnøkkel på en annen enhet?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Dette verktøyet for passordlagring lagrer passord og tilgangsnøkler, så det blir lett å logge på."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 1324df1..f98ffff9 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"अर्को ठाउँमा बनाउनुहोस्"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"अर्को ठाउँमा सेभ गर्नुहोस्"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"अर्को डिभाइस प्रयोग गर्नुहोस्"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"अर्को डिभाइसमा सेभ गर्नुहोस्"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> सेभ गर्ने ठाउँ छनौट गर्नुहोस्"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"आफ्ना पासकीहरू बाउनुहोस्"</string>
- <string name="save_your_password" msgid="6597736507991704307">"आफ्नो पासवर्ड सेभ गर्नुहोस्"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"आफ्नो साइन इनसम्बन्धी जानकारी सेभ गर्नुहोस्"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"तपाईंको जानकारी सेभ गर्न कुनै पासवर्ड म्यानेजर चयन गर्नुहोस् र अर्को टपक अझ चाँडो साइन एन गर्नुहोस्।"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"तपाईं जुनसुकै डिभाइसमा आफ्नो <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> प्रयोग गर्न सक्नुहुन्छ। यो क्रिडेन्सियल <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> का लागि <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"अर्को डिभाइसमा पासकी बनाउने हो?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"तपाईं सजिलै साइन इन गर्न सक्नुहोस् भन्नाका लागि यो पासवर्ड म्यानेजरले तपाईंका पासवर्ड तथा पासकीहरू सेभ गर्ने छ।"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 4d373be..6bc731b 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Op een andere locatie maken"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Op een andere locatie opslaan"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Een ander apparaat gebruiken"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Opslaan op een ander apparaat"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Een locatie kiezen voor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"je toegangssleutels maken"</string>
- <string name="save_your_password" msgid="6597736507991704307">"je wachtwoord opslaan"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"je inloggegevens opslaan"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecteer een wachtwoordmanager om je informatie op te slaan en de volgende keer sneller in te loggen."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Je kunt je <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> voor <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> op elk apparaat gebruiken. Dit wordt opgeslagen in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> voor <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Toegangssleutel maken op een ander apparaat?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> elke keer gebruiken als je inlogt?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Deze wachtwoordmanager slaat je wachtwoorden en toegangssleutels op zodat je makkelijk kunt inloggen."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7db9821..f2655c8 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ତିଆରି କରନ୍ତୁ"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ସେଭ କରନ୍ତୁ"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ଅନ୍ୟ ଏହି ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ସେଭ କରନ୍ତୁ"</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="choose_provider_title" msgid="7245243990139698508">"କେଉଁଠି <xliff:g id="CREATETYPES">%1$s</xliff:g> କରିବେ, ତାହା ବାଛନ୍ତୁ"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ଆପଣଙ୍କ ପାସକୀଗୁଡ଼ିକ ତିଆରି କରନ୍ତୁ"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ଆପଣଙ୍କ ପାସୱାର୍ଡ ସେଭ କରନ୍ତୁ"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ଆପଣଙ୍କ ସାଇନ-ଇନ ସୂଚନା ସେଭ କରନ୍ତୁ"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ଆପଣଙ୍କ ସୂଚନା ସେଭ କରି ପରବର୍ତ୍ତୀ ସମୟରେ ଶୀଘ୍ର ସାଇନ ଇନ କରିବା ପାଇଁ ଏକ Password Manager ଚୟନ କରନ୍ତୁ।"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"ଆପଣ ଯେ କୌଣସି ଡିଭାଇସରେ ଆପଣଙ୍କ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>କୁ ବ୍ୟବହାର କରିପାରିବେ। ଏହାକୁ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ପାଇଁ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ପାସକୀ ତିଆରି କରିବେ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ଏହି Password Manager ସହଜରେ ସାଇନ ଇନ କରିବାରେ ଆପଣଙ୍କୁ ସାହାଯ୍ୟ କରିବା ପାଇଁ ଆପଣଙ୍କ ପାସୱାର୍ଡ ଏବଂ ପାସକୀଗୁଡ଼ିକୁ ଷ୍ଟୋର କରିବ।"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 b9d72f8..824b5db 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਬਣਾਓ"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ਕੋਈ ਹੋਰ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ਲਈ ਕੋਈ ਥਾਂ ਚੁਣੋ"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ਆਪਣੀਆਂ ਪਾਸਕੀਆਂ ਬਣਾਓ"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ਆਪਣਾ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ਆਪਣੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ਆਪਣੀ ਜਾਣਕਾਰੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਅਤੇ ਅਗਲੀ ਵਾਰ ਤੇਜ਼ੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਚੁਣੋ।"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"ਤੁਸੀਂ ਕਿਸੇ ਵੀ ਡੀਵਾਈਸ \'ਤੇ ਆਪਣੀ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। ਇਸਨੂੰ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ਲਈ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"ਕੀ ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ ਵਿੱਚ ਕੋਈ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"ਇਹ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਆਸਾਨੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਾਸਕੀਆਂ ਨੂੰ ਸਟੋਰ ਕਰੇਗਾ।"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 503e8e8..8ba182d 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Utwórz w innym miejscu"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Zapisz w innym miejscu"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Użyj innego urządzenia"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Zapisz na innym urządzeniu"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Wybierz, gdzie chcesz <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"tworzyć klucze"</string>
- <string name="save_your_password" msgid="6597736507991704307">"zapisać hasło"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"zapisać dane logowania"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Wybierz menedżera haseł, aby zapisywać informacje i logować się szybciej."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Elementu typu <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> dla aplikacji <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> możesz używać na każdym urządzeniu. Jest zapisany w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Utworzyć klucz na innym urządzeniu?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Menedżer haseł będzie zapisywał Twoje hasła i klucze, aby ułatwić Ci logowanie."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 0ee1ef6..7aac738 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Criar em outro lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crie suas chaves de acesso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecione um gerenciador de senhas para salvar suas informações e fazer login rapidamente na próxima vez."</string>
+ <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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvar senha do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Você pode usar a <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> do app <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> em qualquer dispositivo. Ela fica salva no <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> de <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
+ <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
+ <string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso em outro dispositivo?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Criar chave de acesso em outro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Esse gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login"</string>
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index 7376ab2..df8477e 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Criar noutro lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar noutro lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar noutro dispositivo"</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="choose_provider_title" msgid="7245243990139698508">"Escolha onde quer guardar <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"criar as suas chaves de acesso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"guardar a sua palavra-passe"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar as suas informações de início de sessão"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"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_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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Guardar a palavra-passe da app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Guardar as informações de início de sessão da app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Pode usar <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> de <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> em qualquer dispositivo. É guardada no <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> de <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"palavra-passe"</string>
+ <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
+ <string name="passwords" msgid="5419394230391253816">"palavras-passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"inícios de sessão"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de início de sessão"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Guarde <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso noutro dispositivo?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Criar chave de acesso noutro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus inícios de sessão?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gestor de palavras-passe armazena as suas palavras-passe e chaves de acesso para ajudar a iniciar sessão facilmente."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Este gestor de palavras-passe armazena as suas palavras-passe e chaves de acesso para ajudar a iniciar sessão facilmente"</string>
<string name="set_as_default" msgid="4415328591568654603">"Definir como predefinição"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> palavras-passe • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index 0ee1ef6..7aac738 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"Criar em outro lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"crie suas chaves de acesso"</string>
- <string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selecione um gerenciador de senhas para salvar suas informações e fazer login rapidamente na próxima vez."</string>
+ <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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvar senha do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Você pode usar a <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> do app <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> em qualquer dispositivo. Ela fica salva no <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> de <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
+ <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
+ <string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso em outro dispositivo?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Criar chave de acesso em outro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Esse gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login"</string>
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 0ccd242..10ff472 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Creează în alt loc"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvează în alt loc"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Folosește alt dispozitiv"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvează pe alt dispozitiv"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Alege unde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"creează cheile de acces"</string>
- <string name="save_your_password" msgid="6597736507991704307">"salvează parola"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvează informațiile de conectare"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Selectează un manager de parole pentru a salva informațiile și a te conecta mai rapid data viitoare."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Poți folosi <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> pe orice dispozitiv. Se salvează în <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pentru <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Creezi o cheie de acces în alt dispozitiv?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Folosești <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pentru toate conectările?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Managerul de parole îți va stoca parolele și cheile de acces, pentru a te ajuta să te conectezi cu ușurință."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 4528563..9a0d979 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Создать в другом месте"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Сохранить в другом месте"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Использовать другое устройство"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Сохранить на другом устройстве"</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="choose_provider_title" msgid="7245243990139698508">"Выберите, где <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"создать ключи доступа"</string>
- <string name="save_your_password" msgid="6597736507991704307">"сохранить пароль"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"сохранить данные для входа"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Выберите менеджер паролей, чтобы сохранять учетные данные и быстро выполнять вход."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Вы можете использовать <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> для приложения \"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>\" на любом устройстве. Данные <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> сохраняются в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"Создать ключ доступа на другом устройстве?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"В этом менеджере паролей можно сохранять учетные данные, например ключи доступа, чтобы потом использовать их."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 e5084d8f..11a7a38 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"වෙනත් ස්ථානයක තනන්න"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"වෙනත් ස්ථානයකට සුරකින්න"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"වෙනත් උපාංගයක් භාවිතා කරන්න"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"වෙනත් උපාංගයකට සුරකින්න"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> කොතැනක ද යන්න තෝරා ගන්න"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ඔබේ මුරයතුරු තනන්න"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ඔබේ මුරපදය සුරකින්න"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ඔබේ පුරනය වීමේ තතු සුරකින්න"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"ඔබේ තතු සුරැකීමට සහ මීළඟ වතාවේ වේගයෙන් පුරනය වීමට මුරපද කළමනාකරුවෙකු තෝරන්න."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"ඔබට ඕනෑම උපාංගයක ඔබේ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> භාවිතා කළ හැක. එය <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> සඳහා <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"වෙනත් උපාංගයක මුරයතුරක් තනන්න ද?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"මෙම මුරපද කළමනාකරු ඔබට පහසුවෙන් පුරනය වීමට උදවු කිරීම සඳහා ඔබේ මුරපද සහ මුරයතුරු ගබඩා කරනු ඇත."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7da7d63..eba5779 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Vytvoriť inde"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Uložiť inde"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Použiť iné zariadenie"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Uložiť do iného zariadenia"</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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Vyberte, kam <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"vytvoriť prístupové kľúče"</string>
- <string name="save_your_password" msgid="6597736507991704307">"uložiť heslo"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"uložiť prihlasovacie údaje"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Vyberte si správcu hesiel, do ktorého sa budú ukladať vaše údaje, aby ste sa nabudúce rýchlejšie prihlásili."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Pripomíname, že <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> aplikácie <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> môžete používať v ľubovoľnom zariadení. Uchováva sa v službe <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pre účet <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Chcete vytvoriť prístupový kľúč v inom zariadení?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tento správca hesiel uchová vaše heslá a prístupové kľúče, aby vám pomohol ľahšie sa prihlasovať."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 af3504a..7201f32 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Ustvarjanje na drugem mestu"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Shranjevanje na drugo mesto"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Uporabi drugo napravo"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Shrani v drugo napravo"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Izberite mesto za <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"ustvarjanje ključev za dostop"</string>
- <string name="save_your_password" msgid="6597736507991704307">"shranjevanje gesla"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"shranjevanje podatkov za prijavo"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Izberite upravitelja gesel za shranjevanje podatkov za prijavo, da se boste naslednjič lahko hitreje prijavili."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> za <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> lahko uporabite v kateri koli napravi. Shranjeno je pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>« za »<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite ustvariti ključ za dostop v drugi napravi?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite za vse prijave uporabiti »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"V tem upravitelju gesel bodo shranjeni gesla in ključi za dostop, kar vam bo olajšalo prijavo."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 38a2c22..87cc2fe 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Krijo në një vend tjetër"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Ruaj në një vend tjetër"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Përdor një pajisje tjetër"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Ruaj në një pajisje tjetër"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Zgjidh se ku të <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"do t\'i krijosh çelësat e tu të kalimit"</string>
- <string name="save_your_password" msgid="6597736507991704307">"ruaj fjalëkalimin"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"ruaj informacionet e tua të identifikimit"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"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>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Mund të përdorësh <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> të <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> në çdo pajisje. Ai është i ruajtur te \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\" për <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Të krijohet një çelës kalimi në një pajisje tjetër?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"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>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 a83c629..80c0537 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Направи на другом месту"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Сачувај на другом месту"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Користи други уређај"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Сачувај на други уређај"</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="choose_provider_title" msgid="7245243990139698508">"Одаберите локацију за: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"направите приступне кодове"</string>
- <string name="save_your_password" msgid="6597736507991704307">"сачувајте лозинку"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"сачувајте податке о пријављивању"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Изаберите менаџера лозинки да бисте сачували податке и брже се пријавили следећи пут."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Можете да користите тип домена <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> на било ком уређају. Чува се код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за: <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"Желите да направите приступни кôд на другом уређају?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Овај менаџер лозинки ће чувати лозинке и приступне кодове да бисте се лако пријављивали."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 502f03e..ab8c5aa 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -5,31 +5,25 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Skapa på en annan plats"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Spara på en annan plats"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Använd en annan enhet"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Spara på en annan enhet"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Välj var du <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"skapa nycklar"</string>
- <string name="save_your_password" msgid="6597736507991704307">"spara lösenordet"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"spara inloggningsuppgifterna"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Välj en lösenordshanterare för att spara dina uppgifter och logga in snabbare nästa gång."</string>
+ <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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Vill du spara lösenordet för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vill du spara inloggningsuppgifterna för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Du kan använda <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> för <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> på alla enheter. Du kan spara uppgifterna i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> för <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
<string name="passkey" msgid="632353688396759522">"nyckel"</string>
<string name="password" msgid="6738570945182936667">"lösenord"</string>
+ <string name="passkeys" msgid="5733880786866559847">"nycklar"</string>
+ <string name="passwords" msgid="5419394230391253816">"lösenord"</string>
<string name="sign_ins" msgid="4710739369149469208">"inloggningar"</string>
<string name="sign_in_info" msgid="2627704710674232328">"inloggningsuppgifter"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Spara <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> i"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vill du skapa en nyckel på en annan enhet?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Vill du skapa en nyckel på en annan enhet?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vill du använda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> för alla dina inloggningar?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Den här lösenordshanteraren sparar dina lösenord och nycklar för att underlätta inloggning."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Den här lösenordshanteraren sparar dina lösenord och nycklar för att underlätta inloggning"</string>
<string name="set_as_default" msgid="4415328591568654603">"Ange som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Använd en gång"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> lösenord • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> nycklar"</string>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index 0cba399..1685882 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Unda katika sehemu nyingine"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Hifadhi sehemu nyingine"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Tumia kifaa kingine"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Hifadhi kwenye kifaa kingine"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Chagua mahali pa <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"unda funguo zako za siri"</string>
- <string name="save_your_password" msgid="6597736507991704307">"hifadhi nenosiri lako"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"hifadhi maelezo yako ya kuingia katika akaunti"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Chagua kidhibiti cha manenosiri ili uhifadhi taarifa zako na uingie kwenye akaunti kwa urahisi wakati mwingine."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Unaweza kutumia <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> wa <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> kwenye kifaa chochote. Umehifadhiwa kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> kwa ajili ya <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Ungependa kuunda ufunguo wa siri kwenye kifaa kingine?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Kidhibiti hiki cha manenosiri kitahifadhi manenosiri na funguo zako za siri ili kukusaidia uingie katika akaunti kwa urahisi."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7650803..5c68f66 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"மற்றொரு இடத்தில் உருவாக்கவும்"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"மற்றொரு இடத்தில் சேமிக்கவும்"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"மற்றொரு சாதனத்தைப் பயன்படுத்தவும்"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"வேறொரு சாதனத்தில் சேமியுங்கள்"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே காட்டப்பட வேண்டும் என்பதைத் தேர்வுசெய்தல்"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"உங்கள் கடவுச்சாவிகளை உருவாக்குங்கள்"</string>
- <string name="save_your_password" msgid="6597736507991704307">"உங்கள் கடவுச்சொல்லைச் சேமிக்கவும்"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"உங்கள் உள்நுழைவு தகவலைச் சேமிக்கவும்"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"உங்கள் விவரங்களைச் சேமிக்கவும் அடுத்த முறை வேகமாக உள்நுழையவும் Password Managerரைத் தேர்ந்தெடுக்கவும்."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"உங்கள் <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ஐ எந்தச் சாதனத்தில் வேண்டுமானாலும் பயன்படுத்தலாம். <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>ரில் <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"வேறொரு சாதனத்தில் கடவுச்சாவியை உருவாக்கவா?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"எளிதில் உள்நுழைவதற்கு உதவும் வகையில் இந்த Password Manager உங்கள் கடவுச்சொற்களையும் கடவுச்சாவிகளையும் சேமிக்கும்."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7581bbc..f428ced 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"మరొక స్థలంలో క్రియేట్ చేయండి"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"మరొక స్థలంలో సేవ్ చేయండి"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"మరొక పరికరాన్ని ఉపయోగించండి"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"మరొక పరికరంలో సేవ్ చేయండి"</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="choose_provider_title" msgid="7245243990139698508">"ఎక్కడ <xliff:g id="CREATETYPES">%1$s</xliff:g> చేయాలో ఎంచుకోండి"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"మీ పాస్-కీలను క్రియేట్ చేయండి"</string>
- <string name="save_your_password" msgid="6597736507991704307">"మీ పాస్వర్డ్ను సేవ్ చేయండి"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"మీ సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయండి"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"మీ సమాచారాన్ని సేవ్ చేయడం కోసం ఒక Password Managerను ఎంచుకొని, తర్వాతసారి వేగంగా సైన్ ఇన్ చేయండి."</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>
<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="choose_create_option_description" msgid="5531335144879100664">"మీరు మీ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>ను ఏ పరికరంలోనైనా ఉపయోగించవచ్చు. ఇది <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> కోసం <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>లో సేవ్ చేయబడింది."</string>
<string name="passkey" msgid="632353688396759522">"పాస్-కీ"</string>
<string name="password" msgid="6738570945182936667">"పాస్వర్డ్"</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="6372952459932674632">"మరొక పరికరంలో పాస్-కీని క్రియేట్ చేయాలా?"</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="6560593199974037820">"మీరు సులభంగా సైన్ ఇన్ చేయడంలో సహాయపడటానికి ఈ పాస్వర్డ్ మేనేజర్ మీ పాస్వర్డ్లు, పాస్-కీలను స్టోర్ చేస్తుంది."</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-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index 8dc3357..5362d48 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"สร้างในตำแหน่งอื่น"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"บันทึกลงในตำแหน่งอื่น"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"ใช้อุปกรณ์อื่น"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"ย้ายไปยังอุปกรณ์อื่น"</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="choose_provider_title" msgid="7245243990139698508">"เลือกตำแหน่งที่จะ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"สร้างพาสคีย์"</string>
- <string name="save_your_password" msgid="6597736507991704307">"บันทึกรหัสผ่าน"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"บันทึกข้อมูลการลงชื่อเข้าใช้"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"เลือกเครื่องมือจัดการรหัสผ่านเพื่อบันทึกข้อมูลและลงชื่อเข้าใช้เร็วขึ้นในครั้งถัดไป"</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="choose_create_option_description" msgid="5531335144879100664">"คุณสามารถใช้ <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> ของ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> ในอุปกรณ์ใดก็ได้ โดยระบบจะบันทึกลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> สำหรับ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
<string name="passkey" msgid="632353688396759522">"พาสคีย์"</string>
<string name="password" msgid="6738570945182936667">"รหัสผ่าน"</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="6372952459932674632">"สร้างพาสคีย์ในอุปกรณ์อื่นไหม"</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="6560593199974037820">"เครื่องมือจัดการรหัสผ่านนี้จะจัดเก็บรหัสผ่านและพาสคีย์ไว้เพื่อช่วยให้คุณลงชื่อเข้าใช้ได้โดยง่าย"</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-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index d3328a5..633c3a0 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -5,31 +5,25 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Gumawa sa ibang lugar"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"I-save sa ibang lugar"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Gumamit ng ibang device"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"I-save sa ibang device"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Piliin kung saan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"gawin ang iyong mga passkey"</string>
- <string name="save_your_password" msgid="6597736507991704307">"i-save ang iyong password"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"i-save ang iyong impormasyon sa pag-sign in"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"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_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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"I-save ang password para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"I-save ang impormasyon sa pag-sign in para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"Magagamit mo ang iyong <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> sa anumang device. Naka-save ito sa <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para sa <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
+ <string name="passkeys" msgid="5733880786866559847">"mga passkey"</string>
+ <string name="passwords" msgid="5419394230391253816">"mga password"</string>
<string name="sign_ins" msgid="4710739369149469208">"mga sign-in"</string>
<string name="sign_in_info" msgid="2627704710674232328">"impormasyon sa pag-sign in"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"I-save ang <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> sa"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Gumawa ng passkey sa ibang device?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Gumawa ng passkey sa ibang device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gamitin ang <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para sa lahat ng iyong pag-sign in?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Iso-store ng password manager na ito ang iyong mga password at passkey para madali kang makapag-sign in."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Iso-store ng password manager na ito ang iyong mga password at passkey para madali kang makapag-sign in"</string>
<string name="set_as_default" msgid="4415328591568654603">"Itakda bilang default"</string>
<string name="use_once" msgid="9027366575315399714">"Gamitin nang isang beses"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> (na) password • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> (na) passkey"</string>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index c315a20..3627e6c 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Başka bir yerde oluşturun"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Başka bir yere kaydedin"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Başka bir cihaz kullan"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Başka bir cihaza kaydet"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> yerini seçin"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"şifre anahtarlarınızı oluşturun"</string>
- <string name="save_your_password" msgid="6597736507991704307">"şifrenizi kaydedin"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"oturum açma bilgilerinizi kaydedin"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Bilgilerinizi kaydedip bir dahaki sefere daha hızlı oturum açmak için bir şifre yöneticisi seçin."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> herhangi bir cihazda kullanılabilir. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> için <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> içine kaydedilir."</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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Başka bir cihazda şifre anahtarı oluşturulsun mu?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Bu şifre yöneticisi, şifrelerinizi ve şifre anahtarlarınızı saklayarak kolayca oturum açmanıza yardımcı olur."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 cb33665..49ef6c1 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"Створити в іншому місці"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Зберегти в іншому місці"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Скористатись іншим пристроєм"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Зберегти на іншому пристрої"</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="choose_provider_title" msgid="7245243990139698508">"Виберіть, де <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"створювати ключі доступу"</string>
- <string name="save_your_password" msgid="6597736507991704307">"зберегти пароль"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"зберегти дані для входу"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Виберіть менеджер паролів, щоб зберігати свої дані й надалі входити в облікові записи швидше."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Ви зможете використовувати <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> додатка <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> на будь-якому пристрої. Ці дані зберігаються в сервісі <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> для користувача <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"Створити ключ доступу на іншому пристрої?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"Цей менеджер паролів зберігатиме ваші паролі та ключі доступу, щоб ви могли легко входити в облікові записи."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 91e8ee7..8ceb842 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"دوسرے مقام میں تخلیق کریں"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"دوسرے مقام میں محفوظ کریں"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"کوئی دوسرا آلہ استعمال کریں"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"دوسرے آلے میں محفوظ کریں"</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="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> کی جگہ منتخب کریں"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"اپنی پاس کیز تخلیق کریں"</string>
- <string name="save_your_password" msgid="6597736507991704307">"اپنا پاس ورڈ محفوظ کریں"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"اپنے سائن ان کی معلومات محفوظ کریں"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"اپنی معلومات کو محفوظ کرنے اور اگلی بار تیز سائن کے لیے پاس ورڈ مینیجر منتخب کریں۔"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"آپ کسی بھی آلے پر اپنا <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> استعمال کر سکتے ہیں۔ یہ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> کے لیے <xliff:g id="PROVIDERINFODISPLAYNAME">%3$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="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="6372952459932674632">"کسی اور آلے میں پاس کی تخلیق کریں؟"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"یہ پاس ورڈ مینیجر آپ کے پاس ورڈز اور پاس کیز کو آسانی سے سائن ان کرنے میں آپ کی مدد کرنے کے لیے اسٹور کرے گا۔"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 cf51f03..9233a53 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -5,31 +5,25 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Boshqa joyda yaratish"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Boshqa joyga saqlash"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Boshqa qurilmadan foydalaning"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Boshqa qurilmaga saqlash"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> joyini tanlang"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"kodlar yaratish"</string>
- <string name="save_your_password" msgid="6597736507991704307">"Parolni saqlash"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"kirish axborotini saqlang"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Maʼlumotlaringizni saqlash va keyingi safar tez kirish uchun parollar menejerini tanlang"</string>
+ <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>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun parol saqlansinmi?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun kirish maʼlumoti saqlansinmi?"</string>
- <string name="choose_create_option_description" msgid="5531335144879100664">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> istalgan qurilmada ishlatilishi mumkin. U <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> uchun <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> xizmatiga saqlandi"</string>
<string name="passkey" msgid="632353688396759522">"kalit"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
+ <string name="passkeys" msgid="5733880786866559847">"kodlar"</string>
+ <string name="passwords" msgid="5419394230391253816">"parollar"</string>
<string name="sign_ins" msgid="4710739369149469208">"kirishlar"</string>
<string name="sign_in_info" msgid="2627704710674232328">"kirish maʼlumoti"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g>ni saqlash"</string>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Boshqa qurilmada kod yaratilsinmi?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Boshqa qurilmada kod yaratilsinmi?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Hamma kirishlarda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ishlatilsinmi?"</string>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Bu parollar menejerida hisobga oson kirishga yordam beruvchi parol va kalitlar saqlanadi."</string>
+ <string name="use_provider_for_all_description" msgid="8466427781848268490">"Bu parollar menejerida hisobga oson kirishga yordam beruvchi parol va kalitlar saqlanadi"</string>
<string name="set_as_default" msgid="4415328591568654603">"Birlamchi deb belgilash"</string>
<string name="use_once" msgid="9027366575315399714">"Bir marta ishlatish"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ta parol • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ta kod"</string>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index 5102625..94111a7 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Tạo ở vị trí khác"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Lưu vào vị trí khác"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Dùng thiết bị khác"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Lưu vào thiết bị khác"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Chọn vị trí <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"tạo mã xác thực"</string>
- <string name="save_your_password" msgid="6597736507991704307">"lưu mật khẩu của bạn"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"lưu thông tin đăng nhập của bạn"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"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>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Bạn có thể sử dụng <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> trên mọi thiết bị. Thông tin này được lưu vào <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> cho <xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Tạo mã xác thực trong một thiết bị khác?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"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>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 fcc8b02..1fc42bd 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -5,31 +5,31 @@
<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_create_in_another_place" msgid="1033635365843437603">"在另一位置创建"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"保存到另一位置"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"使用另一台设备"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"保存到其他设备"</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="choose_provider_title" msgid="7245243990139698508">"选择<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"创建通行密钥"</string>
- <string name="save_your_password" msgid="6597736507991704307">"保存您的密码"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"保存您的登录信息"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"请选择一款密码管理工具来保存您的信息,以便下次更快地登录。"</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"您可以在任意设备上使用“<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>”<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>。系统会将此信息保存到<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>,以供<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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="6372952459932674632">"在其他设备上创建通行密钥?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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="6560593199974037820">"此密码管理工具将会存储您的密码和通行密钥,以帮助您轻松登录。"</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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 7c150bd..276b936 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"在其他位置建立"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</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="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"建立密鑰"</string>
- <string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資料"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"選取密碼管理工具即可儲存自己的資料,縮短下次登入的時間。"</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="choose_create_option_description" msgid="5531335144879100664">"您可以在任何裝置上使用「<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>」<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>。系統會將此資料儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>」,供「<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>」使用"</string>
<string name="passkey" msgid="632353688396759522">"密鑰"</string>
<string name="password" msgid="6738570945182936667">"密碼"</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="6372952459932674632">"要在另一部裝置上建立密鑰嗎?"</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="6560593199974037820">"此密碼管理工具將儲存您的密碼和密鑰,協助您輕鬆登入。"</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 a8b19c8..910756e 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -5,31 +5,25 @@
<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_create_in_another_place" msgid="1033635365843437603">"在其他位置建立"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</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="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"建立金鑰密碼"</string>
- <string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資訊"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"選取密碼管理工具即可儲存你的資訊,下次就能更快登入。"</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="choose_create_option_description" msgid="5531335144879100664">"你可以在任何裝置上使用「<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>」<xliff:g id="CREDENTIALTYPES">%2$s</xliff:g>。這項資料會儲存至 <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>,以供 <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> 使用。"</string>
<string name="passkey" msgid="632353688396759522">"密碼金鑰"</string>
<string name="password" msgid="6738570945182936667">"密碼"</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="6372952459932674632">"要在另一部裝置上建立密碼金鑰嗎?"</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="6560593199974037820">"這個密碼管理工具會儲存你的密碼和密碼金鑰,協助你輕鬆登入。"</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-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index f17c1df..ab56435 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -5,31 +5,31 @@
<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>
- <string name="string_create_in_another_place" msgid="1033635365843437603">"Sungula kwenye indawo"</string>
- <string name="string_save_to_another_place" msgid="7590325934591079193">"Londoloza kwenye indawo"</string>
- <string name="string_use_another_device" msgid="8754514926121520445">"Sebenzisa enye idivayisi"</string>
- <string name="string_save_to_another_device" msgid="1959562542075194458">"Londoloza kwenye idivayisi"</string>
<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>
- <string name="choose_provider_title" msgid="7245243990139698508">"Khetha lapho onga-<xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <string name="create_your_passkeys" msgid="8901224153607590596">"sungula okhiye bakho bokudlula"</string>
- <string name="save_your_password" msgid="6597736507991704307">"Londoloza iphasiwedi yakho"</string>
- <string name="save_your_sign_in_info" msgid="7213978049817076882">"londoloza ulwazi lwakho lokungena ngemvume"</string>
- <string name="choose_provider_body" msgid="4384188171872005547">"Khetha isiphathi sephasiwedi ukuze ulondoloze ulwazi lwakho futhi ungene ngemvume ngokushesha ngesikhathi esizayo."</string>
+ <!-- no translation found for choose_provider_title (8870795677024868108) -->
+ <skip />
+ <!-- no translation found for choose_provider_body (4967074531845147434) -->
+ <skip />
<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="choose_create_option_description" msgid="5531335144879100664">"Ungasebenzisa i-<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="CREDENTIALTYPES">%2$s</xliff:g> yakho kunoma iyiphi idivayisi. Ilondolozwe ku-<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ye-<xliff:g id="CREATEINFODISPLAYNAME">%4$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="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>
- <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Sungula ukhiye wokudlula kwenye idivayisi?"</string>
+ <!-- no translation found for create_passkey_in_other_device_title (9195411122362461390) -->
+ <skip />
<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>
- <string name="use_provider_for_all_description" msgid="6560593199974037820">"Lesi siphathi sephasiwedi sizogcina amaphasiwedi akho nezikhiye zokungena ukuze zikusize ungene ngemvume kalula."</string>
+ <!-- no translation found for use_provider_for_all_description (8466427781848268490) -->
+ <skip />
<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/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index aea51b1..3ec4366a 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -22,5 +22,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
+ "com.android.healthconnect",
],
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index a81e2e3..4d8b89b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -49,7 +49,7 @@
import com.android.settingslib.spa.framework.compose.localNavController
import com.android.settingslib.spa.framework.compose.rememberAnimatedNavController
import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.framework.util.PageEvent
+import com.android.settingslib.spa.framework.util.PageWithEvent
import com.android.settingslib.spa.framework.util.getDestination
import com.android.settingslib.spa.framework.util.getEntryId
import com.android.settingslib.spa.framework.util.getSessionName
@@ -118,32 +118,25 @@
arguments = spp.parameter,
enterTransition = {
slideIntoContainer(
- AnimatedContentScope.SlideDirection.Left,
- animationSpec = slideEffect
+ AnimatedContentScope.SlideDirection.Left, animationSpec = slideEffect
) + fadeIn(animationSpec = fadeEffect)
},
exitTransition = {
slideOutOfContainer(
- AnimatedContentScope.SlideDirection.Left,
- animationSpec = slideEffect
+ AnimatedContentScope.SlideDirection.Left, animationSpec = slideEffect
) + fadeOut(animationSpec = fadeEffect)
},
popEnterTransition = {
slideIntoContainer(
- AnimatedContentScope.SlideDirection.Right,
- animationSpec = slideEffect
+ AnimatedContentScope.SlideDirection.Right, animationSpec = slideEffect
) + fadeIn(animationSpec = fadeEffect)
},
popExitTransition = {
slideOutOfContainer(
- AnimatedContentScope.SlideDirection.Right,
- animationSpec = slideEffect
+ AnimatedContentScope.SlideDirection.Right, animationSpec = slideEffect
) + fadeOut(animationSpec = fadeEffect)
},
- ) { navBackStackEntry ->
- spp.PageEvent(navBackStackEntry.arguments)
- spp.Page(navBackStackEntry.arguments)
- }
+ ) { navBackStackEntry -> spp.PageWithEvent(navBackStackEntry.arguments) }
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 0871304..2175e55 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -185,6 +185,8 @@
private var sliceDataFn: SliceDataGetter = { _: Uri, _: Bundle? -> null }
fun build(): SettingsEntry {
+ val page = fromPage ?: owner
+ val isEnabled = page.isEnabled()
return SettingsEntry(
id = id(),
name = name,
@@ -196,10 +198,10 @@
toPage = toPage,
// attributes
- isAllowSearch = isAllowSearch,
+ isAllowSearch = isEnabled && isAllowSearch,
isSearchDataDynamic = isSearchDataDynamic,
hasMutableStatus = hasMutableStatus,
- hasSliceSupport = hasSliceSupport,
+ hasSliceSupport = isEnabled && hasSliceSupport,
// functions
statusDataImpl = statusDataFn,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
index 2bfa2a4..a362877 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
@@ -94,6 +94,12 @@
return !isCreateBy(NULL_PAGE_NAME) &&
!hasRuntimeParam()
}
+
+ fun isEnabled(): Boolean {
+ if (!SpaEnvironmentFactory.isReady()) return false
+ val pageProviderRepository by SpaEnvironmentFactory.instance.pageProviderRepository
+ return pageProviderRepository.getProviderOrNull(sppName)?.isEnabled(arguments) ?: false
+ }
}
fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
index 940005d..42e5f7e 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
@@ -37,6 +37,14 @@
val parameter: List<NamedNavArgument>
get() = emptyList()
+ /**
+ * The API to indicate whether the page is enabled or not.
+ * During SPA page migration, one can use it to enable certain pages in one release.
+ * When the page is disabled, all its related functionalities, such as browsing, search,
+ * slice provider, are disabled as well.
+ */
+ fun isEnabled(arguments: Bundle?): Boolean = true
+
fun getTitle(arguments: Bundle?): String = displayName
fun buildEntry(arguments: Bundle?): List<SettingsEntry> = emptyList()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
index 73eae07..22a4563 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
@@ -33,13 +33,15 @@
import com.android.settingslib.spa.framework.compose.NavControllerWrapper
@Composable
-internal fun SettingsPageProvider.PageEvent(arguments: Bundle? = null) {
+internal fun SettingsPageProvider.PageWithEvent(arguments: Bundle? = null) {
+ if (!isEnabled(arguments)) return
val page = remember(arguments) { createSettingsPage(arguments) }
val navController = LocalNavController.current
LifecycleEffect(
onStart = { page.logPageEvent(LogEvent.PAGE_ENTER, navController) },
onStop = { page.logPageEvent(LogEvent.PAGE_LEAVE, navController) },
)
+ Page(arguments)
}
private fun SettingsPage.logPageEvent(event: LogEvent, navController: NavControllerWrapper) {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
index bd5884d..218f569 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
import com.android.settingslib.spa.tests.testutils.SpaLoggerForTest
+import com.android.settingslib.spa.tests.testutils.SppDisabled
import com.android.settingslib.spa.tests.testutils.SppHome
import com.android.settingslib.spa.testutils.waitUntil
import com.google.common.truth.Truth
@@ -46,12 +47,12 @@
private val context: Context = ApplicationProvider.getApplicationContext()
private val spaLogger = SpaLoggerForTest()
- private val spaEnvironment =
- SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()), logger = spaLogger)
@Test
fun testBrowsePage() {
spaLogger.reset()
+ val spaEnvironment =
+ SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()), logger = spaLogger)
SpaEnvironmentFactory.reset(spaEnvironment)
val sppRepository by spaEnvironment.pageProviderRepository
@@ -75,6 +76,24 @@
spaLogger.verifyPageEvent(pageHome.id, 1, 1)
spaLogger.verifyPageEvent(pageLayer1.id, 1, 0)
}
+
+ @Test
+ fun testBrowseDisabledPage() {
+ spaLogger.reset()
+ val spaEnvironment = SpaEnvironmentForTest(
+ context, listOf(SppDisabled.createSettingsPage()), logger = spaLogger
+ )
+ SpaEnvironmentFactory.reset(spaEnvironment)
+
+ val sppRepository by spaEnvironment.pageProviderRepository
+ val sppDisabled = sppRepository.getProviderOrNull("SppDisabled")!!
+ val pageDisabled = sppDisabled.createSettingsPage()
+
+ composeTestRule.setContent { BrowseContent(sppRepository) }
+
+ composeTestRule.onNodeWithText(sppDisabled.getTitle(null)).assertDoesNotExist()
+ spaLogger.verifyPageEvent(pageDisabled.id, 0, 0)
+ }
}
private fun SpaLoggerForTest.verifyPageEvent(id: String, entryCount: Int, leaveCount: Int) {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index b600ac6..6de1ae5 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -16,13 +16,16 @@
package com.android.settingslib.spa.framework.common
+import android.content.Context
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.core.os.bundleOf
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.slice.appendSpaParams
import com.android.settingslib.spa.slice.getEntryId
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
import com.android.settingslib.spa.tests.testutils.getUniqueEntryId
import com.android.settingslib.spa.tests.testutils.getUniquePageId
import com.google.common.truth.Truth.assertThat
@@ -53,6 +56,9 @@
@RunWith(AndroidJUnit4::class)
class SettingsEntryTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val spaEnvironment = SpaEnvironmentForTest(context)
+
@get:Rule
val composeTestRule = createComposeRule()
@@ -77,15 +83,15 @@
val owner = SettingsPage.create("mySpp")
val fromPage = SettingsPage.create("fromSpp")
val toPage = SettingsPage.create("toSpp")
- val entryFrom = SettingsEntryBuilder.createLinkFrom("myEntry", owner)
- .setLink(toPage = toPage).build()
+ val entryFrom =
+ SettingsEntryBuilder.createLinkFrom("myEntry", owner).setLink(toPage = toPage).build()
assertThat(entryFrom.id).isEqualTo(getUniqueEntryId("myEntry", owner, owner, toPage))
assertThat(entryFrom.displayName).isEqualTo("myEntry")
assertThat(entryFrom.fromPage!!.sppName).isEqualTo("mySpp")
assertThat(entryFrom.toPage!!.sppName).isEqualTo("toSpp")
- val entryTo = SettingsEntryBuilder.createLinkTo("myEntry", owner)
- .setLink(fromPage = fromPage).build()
+ val entryTo =
+ SettingsEntryBuilder.createLinkTo("myEntry", owner).setLink(fromPage = fromPage).build()
assertThat(entryTo.id).isEqualTo(getUniqueEntryId("myEntry", owner, fromPage, owner))
assertThat(entryTo.displayName).isEqualTo("myEntry")
assertThat(entryTo.fromPage!!.sppName).isEqualTo("fromSpp")
@@ -98,9 +104,7 @@
val entryInject = SettingsEntryBuilder.createInject(owner).build()
assertThat(entryInject.id).isEqualTo(
getUniqueEntryId(
- INJECT_ENTRY_NAME_TEST,
- owner,
- toPage = owner
+ INJECT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
@@ -114,9 +118,7 @@
val entryInject = SettingsEntryBuilder.createRoot(owner, "myRootEntry").build()
assertThat(entryInject.id).isEqualTo(
getUniqueEntryId(
- ROOT_ENTRY_NAME_TEST,
- owner,
- toPage = owner
+ ROOT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
assertThat(entryInject.displayName).isEqualTo("myRootEntry")
@@ -126,13 +128,15 @@
@Test
fun testSetAttributes() {
- val owner = SettingsPage.create("mySpp")
- val entryBuilder = SettingsEntryBuilder.create(owner, "myEntry")
- .setDisplayName("myEntryDisplay")
- .setIsSearchDataDynamic(false)
- .setHasMutableStatus(true)
- .setSearchDataFn { null }
- .setSliceDataFn { _, _ -> null }
+ SpaEnvironmentFactory.reset(spaEnvironment)
+ val owner = SettingsPage.create("SppHome")
+ val entryBuilder =
+ SettingsEntryBuilder.create(owner, "myEntry")
+ .setDisplayName("myEntryDisplay")
+ .setIsSearchDataDynamic(false)
+ .setHasMutableStatus(true)
+ .setSearchDataFn { null }
+ .setSliceDataFn { _, _ -> null }
val entry = entryBuilder.build()
assertThat(entry.id).isEqualTo(getUniqueEntryId("myEntry", owner))
assertThat(entry.displayName).isEqualTo("myEntryDisplay")
@@ -143,21 +147,52 @@
assertThat(entry.hasMutableStatus).isTrue()
assertThat(entry.hasSliceSupport).isTrue()
+ // Test disabled Spp
+ val ownerDisabled = SettingsPage.create("SppDisabled")
+ val entryBuilderDisabled =
+ SettingsEntryBuilder.create(ownerDisabled, "myEntry")
+ .setDisplayName("myEntryDisplay")
+ .setIsSearchDataDynamic(false)
+ .setHasMutableStatus(true)
+ .setSearchDataFn { null }
+ .setSliceDataFn { _, _ -> null }
+ val entryDisabled = entryBuilderDisabled.build()
+ assertThat(entryDisabled.id).isEqualTo(getUniqueEntryId("myEntry", ownerDisabled))
+ assertThat(entryDisabled.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entryDisabled.fromPage).isNull()
+ assertThat(entryDisabled.toPage).isNull()
+ assertThat(entryDisabled.isAllowSearch).isFalse()
+ assertThat(entryDisabled.isSearchDataDynamic).isFalse()
+ assertThat(entryDisabled.hasMutableStatus).isTrue()
+ assertThat(entryDisabled.hasSliceSupport).isFalse()
+
+ // Clear search data fn
val entry2 = entryBuilder.clearSearchDataFn().build()
assertThat(entry2.isAllowSearch).isFalse()
+
+ // Clear SppHome in spa environment
+ SpaEnvironmentFactory.reset()
+ val entry3 = entryBuilder.build()
+ assertThat(entry3.id).isEqualTo(getUniqueEntryId("myEntry", owner))
+ assertThat(entry3.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entry3.fromPage).isNull()
+ assertThat(entry3.toPage).isNull()
+ assertThat(entry3.isAllowSearch).isFalse()
+ assertThat(entry3.isSearchDataDynamic).isFalse()
+ assertThat(entry3.hasMutableStatus).isTrue()
+ assertThat(entry3.hasSliceSupport).isFalse()
}
@Test
fun testSetMarco() {
- val owner = SettingsPage.create("mySpp", arguments = bundleOf("param" to "v1"))
- val entry = SettingsEntryBuilder.create(owner, "myEntry")
- .setMacro {
- assertThat(it?.getString("param")).isEqualTo("v1")
- assertThat(it?.getString("rtParam")).isEqualTo("v2")
- assertThat(it?.getString("unknown")).isNull()
- MacroForTest(getUniquePageId("mySpp"), getUniqueEntryId("myEntry", owner))
- }
- .build()
+ SpaEnvironmentFactory.reset(spaEnvironment)
+ val owner = SettingsPage.create("SppHome", arguments = bundleOf("param" to "v1"))
+ val entry = SettingsEntryBuilder.create(owner, "myEntry").setMacro {
+ assertThat(it?.getString("param")).isEqualTo("v1")
+ assertThat(it?.getString("rtParam")).isEqualTo("v2")
+ assertThat(it?.getString("unknown")).isNull()
+ MacroForTest(getUniquePageId("SppHome"), getUniqueEntryId("myEntry", owner))
+ }.build()
val rtArguments = bundleOf("rtParam" to "v2")
composeTestRule.setContent { entry.UiLayout(rtArguments) }
@@ -175,14 +210,14 @@
@Test
fun testSetSliceDataFn() {
- val owner = SettingsPage.create("mySpp")
+ SpaEnvironmentFactory.reset(spaEnvironment)
+ val owner = SettingsPage.create("SppHome")
val entryId = getUniqueEntryId("myEntry", owner)
val emptySliceData = EntrySliceData()
- val entryBuilder = SettingsEntryBuilder.create(owner, "myEntry")
- .setSliceDataFn { uri, _ ->
- return@setSliceDataFn if (uri.getEntryId() == entryId) emptySliceData else null
- }
+ val entryBuilder = SettingsEntryBuilder.create(owner, "myEntry").setSliceDataFn { uri, _ ->
+ return@setSliceDataFn if (uri.getEntryId() == entryId) emptySliceData else null
+ }
val entry = entryBuilder.build()
assertThat(entry.id).isEqualTo(entryId)
assertThat(entry.hasSliceSupport).isTrue()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt
index 1bdba29..530d2ed 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt
@@ -23,6 +23,7 @@
import androidx.slice.Slice
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
import com.android.settingslib.spa.tests.testutils.SppHome
@@ -44,6 +45,8 @@
@Test
fun getOrBuildSliceDataTest() {
+ SpaEnvironmentFactory.reset(spaEnvironment)
+
// Slice empty
assertThat(sliceDataRepository.getOrBuildSliceData(Uri.EMPTY)).isNull()
@@ -67,6 +70,8 @@
@Test
fun getActiveSliceDataTest() {
+ SpaEnvironmentFactory.reset(spaEnvironment)
+
val page = SppLayer2.createSettingsPage()
val entryId = getUniqueEntryId("Layer2Entry1", page)
val sliceUri = Uri.Builder().appendSpaParams(page.buildRoute(), entryId).build()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt
index f38bd08..2755b4e 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt
@@ -92,6 +92,23 @@
}
}
+object SppDisabled : SettingsPageProvider {
+ override val name = "SppDisabled"
+
+ override fun isEnabled(arguments: Bundle?): Boolean = false
+
+ override fun getTitle(arguments: Bundle?): String {
+ return "TitleDisabled"
+ }
+
+ override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+ val owner = this.createSettingsPage()
+ return listOf(
+ SppLayer1.buildInject().setLink(fromPage = owner).build(),
+ )
+ }
+}
+
object SppLayer1 : SettingsPageProvider {
override val name = "SppLayer1"
@@ -190,7 +207,7 @@
SettingsPageProviderRepository(
listOf(
SppHome, SppLayer1, SppLayer2,
- SppForSearch,
+ SppForSearch, SppDisabled,
object : SettingsPageProvider {
override val name = "SppWithParam"
override val parameter = listOf(
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 cbb4fbe..ce0c551 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
@@ -26,6 +26,7 @@
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.runBlocking
/**
* The config used to load the App List.
@@ -47,8 +48,21 @@
userIdFlow: Flow<Int>,
showSystemFlow: Flow<Boolean>,
): Flow<(app: ApplicationInfo) -> Boolean>
+
+ /** Gets the system app package names. */
+ fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String>
}
+/**
+ * Util for app list repository.
+ */
+object AppListRepositoryUtil {
+ /** Gets the system app package names. */
+ @JvmStatic
+ fun getSystemPackageNames(context: Context, config: AppListConfig): Set<String> {
+ return AppListRepositoryImpl(context).getSystemPackageNamesBlocking(config)
+ }
+}
internal class AppListRepositoryImpl(private val context: Context) : AppListRepository {
private val packageManager = context.packageManager
@@ -83,15 +97,26 @@
): Flow<(app: ApplicationInfo) -> Boolean> =
userIdFlow.combine(showSystemFlow, ::showSystemPredicate)
+ override fun getSystemPackageNamesBlocking(config: AppListConfig) = runBlocking {
+ getSystemPackageNames(config)
+ }
+
+ 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 showSystemPredicate(
userId: Int,
showSystem: Boolean,
): (app: ApplicationInfo) -> Boolean {
if (showSystem) return { true }
val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId)
- return { app ->
- app.isUpdatedSystemApp || !app.isSystemApp || app.packageName in homeOrLauncherPackages
- }
+ return { app -> !isSystemApp(app, homeOrLauncherPackages) }
}
private suspend fun loadHomeOrLauncherPackages(userId: Int): Set<String> {
@@ -117,6 +142,11 @@
}
}
+ private fun isSystemApp(app: ApplicationInfo, homeOrLauncherPackages: Set<String>): Boolean {
+ return !app.isUpdatedSystemApp && app.isSystemApp &&
+ !(app.packageName in homeOrLauncherPackages)
+ }
+
companion object {
private fun ApplicationInfo.isInAppList(
showInstantApps: Boolean,
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 df828f2..6cd1c0d 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
@@ -51,7 +51,7 @@
}
internal interface IAppListViewModel<T : AppRecord> {
- val option: StateFlowBridge<Int?>
+ val optionFlow: MutableStateFlow<Int?>
val spinnerOptionsFlow: Flow<List<SpinnerOption>>
val appListDataFlow: Flow<AppListData<T>>
}
@@ -69,7 +69,7 @@
val appListConfig = StateFlowBridge<AppListConfig>()
val listModel = StateFlowBridge<AppListModel<T>>()
val showSystem = StateFlowBridge<Boolean>()
- final override val option = StateFlowBridge<Int?>()
+ final override val optionFlow = MutableStateFlow<Int?>(null)
val searchQuery = StateFlowBridge<String>()
private val appListRepository = appListRepositoryFactory(application)
@@ -97,7 +97,7 @@
listModel.getSpinnerOptions(recordList)
}
- override val appListDataFlow = option.flow.flatMapLatest(::filterAndSort)
+ override val appListDataFlow = optionFlow.filterNotNull().flatMapLatest(::filterAndSort)
.combine(searchQuery.flow) { appListData, searchQuery ->
appListData.filter {
it.label.contains(other = searchQuery, ignoreCase = true)
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 34c3ee0..7199e3a 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
@@ -24,11 +24,10 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
@@ -37,7 +36,6 @@
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
import com.android.settingslib.spa.framework.compose.toState
-import com.android.settingslib.spa.framework.util.StateFlowBridge
import com.android.settingslib.spa.widget.ui.CategoryTitle
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
import com.android.settingslib.spa.widget.ui.Spinner
@@ -52,6 +50,7 @@
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IAppListViewModel
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
private const val TAG = "AppList"
private const val CONTENT_TYPE_HEADER = "header"
@@ -88,7 +87,7 @@
val viewModel = viewModelSupplier()
Column(Modifier.fillMaxSize()) {
val optionsState = viewModel.spinnerOptionsFlow.collectAsState(null, Dispatchers.IO)
- SpinnerOptions(optionsState, viewModel.option)
+ SpinnerOptions(optionsState, viewModel.optionFlow)
val appListData = viewModel.appListDataFlow.collectAsState(null, Dispatchers.IO)
listModel.AppListWidget(appListData, header, bottomPadding, noItemMessage)
}
@@ -97,15 +96,18 @@
@Composable
private fun SpinnerOptions(
optionsState: State<List<SpinnerOption>?>,
- optionBridge: StateFlowBridge<Int?>,
+ optionFlow: MutableStateFlow<Int?>,
) {
val options = optionsState.value
- val selectedOption = rememberSaveable(options) {
- mutableStateOf(options?.let { it.firstOrNull()?.id ?: -1 })
+ LaunchedEffect(options) {
+ if (options != null && !options.any { it.id == optionFlow.value }) {
+ // Reset to first option if the available options changed, and the current selected one
+ // does not in the new options.
+ optionFlow.value = options.let { it.firstOrNull()?.id ?: -1 }
+ }
}
- optionBridge.Sync(selectedOption)
if (options != null) {
- Spinner(options, selectedOption.value) { selectedOption.value = it }
+ Spinner(options, optionFlow.collectAsState().value) { optionFlow.value = it }
}
}
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 2d8f009..b0ea40a 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
@@ -180,9 +180,7 @@
@Test
fun showSystemPredicate_showSystem() = runTest {
- val app = ApplicationInfo().apply {
- flags = ApplicationInfo.FLAG_SYSTEM
- }
+ val app = SYSTEM_APP
val showSystemPredicate = getShowSystemPredicate(showSystem = true)
@@ -191,9 +189,7 @@
@Test
fun showSystemPredicate_notShowSystemAndIsSystemApp() = runTest {
- val app = ApplicationInfo().apply {
- flags = ApplicationInfo.FLAG_SYSTEM
- }
+ val app = SYSTEM_APP
val showSystemPredicate = getShowSystemPredicate(showSystem = false)
@@ -202,9 +198,7 @@
@Test
fun showSystemPredicate_isUpdatedSystemApp() = runTest {
- val app = ApplicationInfo().apply {
- flags = ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
- }
+ val app = UPDATED_SYSTEM_APP
val showSystemPredicate = getShowSystemPredicate(showSystem = false)
@@ -213,10 +207,8 @@
@Test
fun showSystemPredicate_isHome() = runTest {
- val app = ApplicationInfo().apply {
- flags = ApplicationInfo.FLAG_SYSTEM
- packageName = "home.app"
- }
+ val app = HOME_APP
+
whenever(packageManager.getHomeActivities(any())).thenAnswer {
@Suppress("UNCHECKED_CAST")
val resolveInfos = it.arguments[0] as MutableList<ResolveInfo>
@@ -231,10 +223,8 @@
@Test
fun showSystemPredicate_appInLauncher() = runTest {
- val app = ApplicationInfo().apply {
- flags = ApplicationInfo.FLAG_SYSTEM
- packageName = "app.in.launcher"
- }
+ val app = IN_LAUMCHER_APP
+
whenever(
packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), eq(USER_ID))
).thenReturn(listOf(resolveInfoOf(packageName = app.packageName)))
@@ -244,6 +234,17 @@
assertThat(showSystemPredicate(app)).isTrue()
}
+ @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)
+
+ val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames(context, appListConfig)
+
+ assertThat(systemPackageNames).containsExactly("system.app", "home.app", "app.in.launcher")
+ }
+
private suspend fun getShowSystemPredicate(showSystem: Boolean) =
repository.showSystemPredicate(
userIdFlow = flowOf(USER_ID),
@@ -264,6 +265,26 @@
privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT
}
+ val SYSTEM_APP = ApplicationInfo().apply {
+ packageName = "system.app"
+ flags = ApplicationInfo.FLAG_SYSTEM
+ }
+
+ val UPDATED_SYSTEM_APP = ApplicationInfo().apply {
+ packageName = "updated.system.app"
+ flags = ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
+ }
+
+ val HOME_APP = ApplicationInfo().apply {
+ packageName = "home.app"
+ flags = ApplicationInfo.FLAG_SYSTEM
+ }
+
+ val IN_LAUMCHER_APP = ApplicationInfo().apply {
+ packageName = "app.in.launcher"
+ flags = ApplicationInfo.FLAG_SYSTEM
+ }
+
fun resolveInfoOf(packageName: String) = ResolveInfo().apply {
activityInfo = ActivityInfo().apply {
this.packageName = packageName
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 f514487..b1d02f5 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
@@ -56,7 +56,7 @@
viewModel.appListConfig.setIfAbsent(CONFIG)
viewModel.listModel.setIfAbsent(listModel)
viewModel.showSystem.setIfAbsent(false)
- viewModel.option.setIfAbsent(0)
+ viewModel.optionFlow.value = 0
viewModel.searchQuery.setIfAbsent("")
viewModel.reloadApps()
return viewModel
@@ -90,6 +90,8 @@
userIdFlow: Flow<Int>,
showSystemFlow: Flow<Boolean>,
): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true }
+
+ override fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String> = setOf()
}
private object FakeAppRepository : AppRepository {
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 2a1f7a4..d5c7c19 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
@@ -29,7 +29,6 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.toState
-import com.android.settingslib.spa.framework.util.StateFlowBridge
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppEntry
@@ -38,6 +37,7 @@
import com.android.settingslib.spaprivileged.model.app.IAppListViewModel
import com.android.settingslib.spaprivileged.tests.testutils.TestAppListModel
import com.android.settingslib.spaprivileged.tests.testutils.TestAppRecord
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import org.junit.Rule
import org.junit.Test
@@ -125,7 +125,7 @@
bottomPadding = 0.dp,
).AppListImpl {
object : IAppListViewModel<TestAppRecord> {
- override val option: StateFlowBridge<Int?> = StateFlowBridge()
+ override val optionFlow: MutableStateFlow<Int?> = MutableStateFlow(null)
override val spinnerOptionsFlow = flowOf(options.mapIndexed { index, option ->
SpinnerOption(id = index, text = option)
})
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index 44a37f4..d4d2b48 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -32,6 +33,9 @@
import com.android.settingslib.R;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
/**
* Utility methods for working with display density.
@@ -70,120 +74,169 @@
*/
private static final int MIN_DIMENSION_DP = 320;
- private final String[] mEntries;
- private final int[] mValues;
+ private static final Predicate<DisplayInfo> INTERNAL_ONLY =
+ (info) -> info.type == Display.TYPE_INTERNAL;
- private final int mDefaultDensity;
- private final int mCurrentIndex;
+ private final Predicate<DisplayInfo> mPredicate;
+
+ private final DisplayManager mDisplayManager;
+
+ /**
+ * The text description of the density values of the default display.
+ */
+ private String[] mDefaultDisplayDensityEntries;
+
+ /**
+ * The density values of the default display.
+ */
+ private int[] mDefaultDisplayDensityValues;
+
+ /**
+ * The density values, indexed by display unique ID.
+ */
+ private final Map<String, int[]> mValuesPerDisplay = new HashMap();
+
+ private int mDefaultDensityForDefaultDisplay;
+ private int mCurrentIndex = -1;
public DisplayDensityUtils(Context context) {
- final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
- Display.DEFAULT_DISPLAY);
- if (defaultDensity <= 0) {
- mEntries = null;
- mValues = null;
- mDefaultDensity = 0;
- mCurrentIndex = -1;
- return;
- }
+ this(context, INTERNAL_ONLY);
+ }
- final Resources res = context.getResources();
- DisplayInfo info = new DisplayInfo();
- context.getDisplayNoVerify().getDisplayInfo(info);
+ /**
+ * Creates an instance that stores the density values for the displays that satisfy
+ * the predicate.
+ * @param context The context
+ * @param predicate Determines what displays the density should be set for. The default display
+ * must satisfy this predicate.
+ */
+ public DisplayDensityUtils(Context context, Predicate predicate) {
+ mPredicate = predicate;
+ mDisplayManager = context.getSystemService(DisplayManager.class);
- final int currentDensity = info.logicalDensityDpi;
- int currentDensityIndex = -1;
-
- // Compute number of "larger" and "smaller" scales for this display.
- final int minDimensionPx = Math.min(info.logicalWidth, info.logicalHeight);
- final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
- final float maxScaleDimen = context.getResources().getFraction(
- R.fraction.display_density_max_scale, 1, 1);
- final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
- final float minScale = context.getResources().getFraction(
- R.fraction.display_density_min_scale, 1, 1);
- final float minScaleInterval = context.getResources().getFraction(
- R.fraction.display_density_min_scale_interval, 1, 1);
- final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
- 0, SUMMARIES_LARGER.length);
- final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
- 0, SUMMARIES_SMALLER.length);
-
- String[] entries = new String[1 + numSmaller + numLarger];
- int[] values = new int[entries.length];
- int curIndex = 0;
-
- if (numSmaller > 0) {
- final float interval = (1 - minScale) / numSmaller;
- for (int i = numSmaller - 1; i >= 0; i--) {
- // Round down to a multiple of 2 by truncating the low bit.
- final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
- }
- entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
- values[curIndex] = density;
- curIndex++;
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Cannot fetch display info for display " + display.getDisplayId());
+ continue;
}
- }
-
- if (currentDensity == defaultDensity) {
- currentDensityIndex = curIndex;
- }
- values[curIndex] = defaultDensity;
- entries[curIndex] = res.getString(SUMMARY_DEFAULT);
- curIndex++;
-
- if (numLarger > 0) {
- final float interval = (maxScale - 1) / numLarger;
- for (int i = 0; i < numLarger; i++) {
- // Round down to a multiple of 2 by truncating the low bit.
- final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
+ if (!mPredicate.test(info)) {
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Predicate must not filter out the default "
+ + "display.");
}
- values[curIndex] = density;
- entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
- curIndex++;
+ continue;
}
+
+ final int defaultDensity = DisplayDensityUtils.getDefaultDensityForDisplay(
+ display.getDisplayId());
+ if (defaultDensity <= 0) {
+ Log.w(LOG_TAG, "Cannot fetch default density for display "
+ + display.getDisplayId());
+ continue;
+ }
+
+ final Resources res = context.getResources();
+
+ final int currentDensity = info.logicalDensityDpi;
+ int currentDensityIndex = -1;
+
+ // Compute number of "larger" and "smaller" scales for this display.
+ final int minDimensionPx = Math.min(info.logicalWidth, info.logicalHeight);
+ final int maxDensity =
+ DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+ final float maxScaleDimen = context.getResources().getFraction(
+ R.fraction.display_density_max_scale, 1, 1);
+ final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
+ final float minScale = context.getResources().getFraction(
+ R.fraction.display_density_min_scale, 1, 1);
+ final float minScaleInterval = context.getResources().getFraction(
+ R.fraction.display_density_min_scale_interval, 1, 1);
+ final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
+ 0, SUMMARIES_LARGER.length);
+ final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
+ 0, SUMMARIES_SMALLER.length);
+
+ String[] entries = new String[1 + numSmaller + numLarger];
+ int[] values = new int[entries.length];
+ int curIndex = 0;
+
+ if (numSmaller > 0) {
+ final float interval = (1 - minScale) / numSmaller;
+ for (int i = numSmaller - 1; i >= 0; i--) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+ values[curIndex] = density;
+ curIndex++;
+ }
+ }
+
+ if (currentDensity == defaultDensity) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = defaultDensity;
+ entries[curIndex] = res.getString(SUMMARY_DEFAULT);
+ curIndex++;
+
+ if (numLarger > 0) {
+ final float interval = (maxScale - 1) / numLarger;
+ for (int i = 0; i < numLarger; i++) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = density;
+ entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+ curIndex++;
+ }
+ }
+
+ final int displayIndex;
+ if (currentDensityIndex >= 0) {
+ displayIndex = currentDensityIndex;
+ } else {
+ // We don't understand the current density. Must have been set by
+ // someone else. Make room for another entry...
+ int newLength = values.length + 1;
+ values = Arrays.copyOf(values, newLength);
+ values[curIndex] = currentDensity;
+
+ entries = Arrays.copyOf(entries, newLength);
+ entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+ displayIndex = curIndex;
+ }
+
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mDefaultDensityForDefaultDisplay = defaultDensity;
+ mCurrentIndex = displayIndex;
+ mDefaultDisplayDensityEntries = entries;
+ mDefaultDisplayDensityValues = values;
+ }
+ mValuesPerDisplay.put(info.uniqueId, values);
}
-
- final int displayIndex;
- if (currentDensityIndex >= 0) {
- displayIndex = currentDensityIndex;
- } else {
- // We don't understand the current density. Must have been set by
- // someone else. Make room for another entry...
- int newLength = values.length + 1;
- values = Arrays.copyOf(values, newLength);
- values[curIndex] = currentDensity;
-
- entries = Arrays.copyOf(entries, newLength);
- entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
-
- displayIndex = curIndex;
- }
-
- mDefaultDensity = defaultDensity;
- mCurrentIndex = displayIndex;
- mEntries = entries;
- mValues = values;
}
- public String[] getEntries() {
- return mEntries;
+ public String[] getDefaultDisplayDensityEntries() {
+ return mDefaultDisplayDensityEntries;
}
- public int[] getValues() {
- return mValues;
+ public int[] getDefaultDisplayDensityValues() {
+ return mDefaultDisplayDensityValues;
}
- public int getCurrentIndex() {
+ public int getCurrentIndexForDefaultDisplay() {
return mCurrentIndex;
}
- public int getDefaultDensity() {
- return mDefaultDensity;
+ public int getDefaultDensityForDefaultDisplay() {
+ return mDefaultDensityForDefaultDisplay;
}
/**
@@ -193,7 +246,7 @@
* @return the default density of the specified display, or {@code -1} if
* the display does not exist or the density could not be obtained
*/
- private static int getDefaultDisplayDensity(int displayId) {
+ private static int getDefaultDensityForDisplay(int displayId) {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
return wm.getInitialDisplayDensity(displayId);
@@ -203,19 +256,31 @@
}
/**
- * Asynchronously applies display density changes to the specified display.
+ * Asynchronously applies display density changes to the displays that satisfy the predicate.
* <p>
* The change will be applied to the user specified by the value of
* {@link UserHandle#myUserId()} at the time the method is called.
- *
- * @param displayId the identifier of the display to modify
*/
- public static void clearForcedDisplayDensity(final int displayId) {
+ public void clearForcedDisplayDensity() {
final int userId = UserHandle.myUserId();
AsyncTask.execute(() -> {
try {
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- wm.clearForcedDisplayDensityForUser(displayId, userId);
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ int displayId = display.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Unable to clear forced display density setting "
+ + "for display " + displayId);
+ continue;
+ }
+ if (!mPredicate.test(info)) {
+ continue;
+ }
+
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.clearForcedDisplayDensityForUser(displayId, userId);
+ }
} catch (RemoteException exc) {
Log.w(LOG_TAG, "Unable to clear forced display density setting");
}
@@ -223,20 +288,39 @@
}
/**
- * Asynchronously applies display density changes to the specified display.
+ * Asynchronously applies display density changes to the displays that satisfy the predicate.
* <p>
* The change will be applied to the user specified by the value of
* {@link UserHandle#myUserId()} at the time the method is called.
*
- * @param displayId the identifier of the display to modify
- * @param density the density to force for the specified display
+ * @param index The index of the density value
*/
- public static void setForcedDisplayDensity(final int displayId, final int density) {
+ public void setForcedDisplayDensity(final int index) {
final int userId = UserHandle.myUserId();
AsyncTask.execute(() -> {
try {
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- wm.setForcedDisplayDensityForUser(displayId, density, userId);
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ int displayId = display.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting "
+ + "for display " + displayId);
+ continue;
+ }
+ if (!mPredicate.test(info)) {
+ continue;
+ }
+ if (!mValuesPerDisplay.containsKey(info.uniqueId)) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting "
+ + "for display " + info.uniqueId);
+ continue;
+ }
+
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.setForcedDisplayDensityForUser(displayId,
+ mValuesPerDisplay.get(info.uniqueId)[index], userId);
+ }
} catch (RemoteException exc) {
Log.w(LOG_TAG, "Unable to save forced display density setting");
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4365a9b..5ee36f3 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -695,6 +695,7 @@
Settings.Secure.BACKUP_AUTO_RESTORE,
Settings.Secure.BACKUP_ENABLED,
Settings.Secure.BACKUP_PROVISIONED,
+ Settings.Secure.BACKUP_SCHEDULING_ENABLED,
Settings.Secure.BACKUP_TRANSPORT,
Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT,
Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 90d3488..115cf792 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -343,6 +343,7 @@
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
+ <protected-broadcast android:name="com.android.systemui.STARTED" />
<application
android:name=".SystemUIApplication"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 5c4fdcc..ed54f08 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -17,6 +17,10 @@
package com.android.systemui.accessibility.accessibilitymenu;
import android.accessibilityservice.AccessibilityService;
+import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -27,23 +31,99 @@
public class AccessibilityMenuService extends AccessibilityService implements View.OnTouchListener {
private static final String TAG = "A11yMenuService";
+ private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
+
private A11yMenuOverlayLayout mA11yMenuLayout;
+ private static boolean sInitialized = false;
+
+ // TODO(b/136716947): Support multi-display once a11y framework side is ready.
+ private DisplayManager mDisplayManager;
+ final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
+ int mRotation;
+
+ @Override
+ public void onDisplayAdded(int displayId) {}
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ // TODO(b/136716947): Need to reset A11yMenuOverlayLayout by display id.
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ if (mRotation != display.getRotation()) {
+ mRotation = display.getRotation();
+ mA11yMenuLayout.updateViewLayout();
+ }
+ }
+ };
+
+ // Update layout.
+ private final Handler mHandler = new Handler(getMainLooper());
+ private final Runnable mOnConfigChangedRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (!sInitialized) {
+ return;
+ }
+ // Re-assign theme to service after onConfigurationChanged
+ getTheme().applyStyle(R.style.ServiceTheme, true);
+ // Caches & updates the page index to ViewPager when a11y menu is refreshed.
+ // Otherwise, the menu page would reset on a UI update.
+ int cachedPageIndex = mA11yMenuLayout.getPageIndex();
+ mA11yMenuLayout.configureLayout(cachedPageIndex);
+ }
+ };
+
@Override
public void onCreate() {
super.onCreate();
}
@Override
+ public void onDestroy() {
+ if (mHandler.hasCallbacks(mOnConfigChangedRunnable)) {
+ mHandler.removeCallbacks(mOnConfigChangedRunnable);
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
protected void onServiceConnected() {
mA11yMenuLayout = new A11yMenuOverlayLayout(this);
- super.onServiceConnected();
+
+ // Temporary measure to force visibility
mA11yMenuLayout.toggleVisibility();
+
+ mDisplayManager = getSystemService(DisplayManager.class);
+ mDisplayManager.registerDisplayListener(mDisplayListener, null);
+
+ sInitialized = true;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {}
+ /**
+ * This method would notify service when device configuration, such as display size,
+ * localization, orientation or theme, is changed.
+ *
+ * @param newConfig the new device configuration.
+ */
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // Prevent update layout failure
+ // if multiple onConfigurationChanged are called at the same time.
+ if (mHandler.hasCallbacks(mOnConfigChangedRunnable)) {
+ mHandler.removeCallbacks(mOnConfigChangedRunnable);
+ }
+ mHandler.postDelayed(
+ mOnConfigChangedRunnable, BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE);
+ }
+
@Override
public void onInterrupt() {
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index 259f0ed..4e96dda 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -41,6 +41,7 @@
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCompositionContext
@@ -73,6 +74,7 @@
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.lifecycle.ViewTreeViewModelStoreOwner
+import com.android.compose.runtime.movableContentOf
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.max
@@ -170,25 +172,25 @@
val contentColor = controller.contentColor
val shape = controller.shape
- // TODO(b/230830644): Use movableContentOf to preserve the content state instead once the
- // Compose libraries have been updated and include aosp/2163631.
val wrappedContent =
- @Composable { controller: ExpandableController ->
- CompositionLocalProvider(
- LocalContentColor provides contentColor,
- ) {
- // We make sure that the content itself (wrapped by the background) is at least
- // 40.dp, which is the same as the M3 buttons. This applies even if onClick is
- // null, to make it easier to write expandables that are sometimes clickable and
- // sometimes not. There shouldn't be any Expandable smaller than 40dp because if
- // the expandable is not clickable directly, then something in its content should
- // be (and with a size >= 40dp).
- val minSize = 40.dp
- Box(
- Modifier.defaultMinSize(minWidth = minSize, minHeight = minSize),
- contentAlignment = Alignment.Center,
+ remember(content) {
+ movableContentOf { expandable: Expandable ->
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor,
) {
- content(controller.expandable)
+ // We make sure that the content itself (wrapped by the background) is at least
+ // 40.dp, which is the same as the M3 buttons. This applies even if onClick is
+ // null, to make it easier to write expandables that are sometimes clickable and
+ // sometimes not. There shouldn't be any Expandable smaller than 40dp because if
+ // the expandable is not clickable directly, then something in its content
+ // should be (and with a size >= 40dp).
+ val minSize = 40.dp
+ Box(
+ Modifier.defaultMinSize(minWidth = minSize, minHeight = minSize),
+ contentAlignment = Alignment.Center,
+ ) {
+ content(expandable)
+ }
}
}
}
@@ -270,7 +272,7 @@
.onGloballyPositioned {
controller.boundsInComposeViewRoot.value = it.boundsInRoot()
}
- ) { wrappedContent(controller) }
+ ) { wrappedContent(controller.expandable) }
}
else -> {
val clickModifier =
@@ -301,7 +303,7 @@
controller.boundsInComposeViewRoot.value = it.boundsInRoot()
},
) {
- wrappedContent(controller)
+ wrappedContent(controller.expandable)
}
}
}
@@ -315,7 +317,7 @@
animatorState: State<LaunchAnimator.State?>,
overlay: ViewGroupOverlay,
controller: ExpandableControllerImpl,
- content: @Composable (ExpandableController) -> Unit,
+ content: @Composable (Expandable) -> Unit,
composeViewRoot: View,
onOverlayComposeViewChanged: (View?) -> Unit,
density: Density,
@@ -370,7 +372,7 @@
// We center the content in the expanding container.
contentAlignment = Alignment.Center,
) {
- Box(contentModifier) { content(controller) }
+ Box(contentModifier) { content(controller.expandable) }
}
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
index 7f2933e..c9e57b4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
@@ -15,21 +15,51 @@
package com.android.systemui.unfold.system
import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration
+import android.os.Trace
+import com.android.systemui.shared.system.TaskStackChangeListener
+import com.android.systemui.shared.system.TaskStackChangeListeners
import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class ActivityManagerActivityTypeProvider @Inject constructor(
- private val activityManager: ActivityManager
-) : CurrentActivityTypeProvider {
+class ActivityManagerActivityTypeProvider
+@Inject
+constructor(private val activityManager: ActivityManager) : CurrentActivityTypeProvider {
override val isHomeActivity: Boolean?
- get() {
- val activityType = activityManager.getRunningTasks(/* maxNum= */ 1)
- ?.getOrNull(0)?.topActivityType ?: return null
+ get() = _isHomeActivity
- return activityType == WindowConfiguration.ACTIVITY_TYPE_HOME
+ private var _isHomeActivity: Boolean? = null
+
+
+ override fun init() {
+ _isHomeActivity = activityManager.isOnHomeActivity()
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(taskStackChangeListener)
+ }
+
+ override fun uninit() {
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(taskStackChangeListener)
+ }
+
+ private val taskStackChangeListener =
+ object : TaskStackChangeListener {
+ override fun onTaskMovedToFront(taskInfo: RunningTaskInfo) {
+ _isHomeActivity = taskInfo.isHomeActivity()
+ }
}
+
+ private fun RunningTaskInfo.isHomeActivity(): Boolean =
+ topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME
+
+ private fun ActivityManager.isOnHomeActivity(): Boolean? {
+ try {
+ Trace.beginSection("isOnHomeActivity")
+ return getRunningTasks(/* maxNum= */ 1)?.firstOrNull()?.isHomeActivity()
+ } finally {
+ Trace.endSection()
+ }
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
index 24ae42a..fe607e1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
@@ -19,7 +19,7 @@
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
import com.android.systemui.unfold.config.UnfoldTransitionConfig
-import com.android.systemui.unfold.dagger.UnfoldBackground
+import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.util.CurrentActivityTypeProvider
@@ -56,6 +56,6 @@
abstract fun mainHandler(@Main handler: Handler): Handler
@Binds
- @UnfoldBackground
+ @UnfoldSingleThreadBg
abstract fun backgroundExecutor(@UiBackground executor: Executor): Executor
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index e4c197f..1404053 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -35,13 +35,13 @@
override val actsAsConfirmButton: Boolean = true
- override fun shouldAnimateForTransition(
+ override fun shouldAnimateIconViewForTransition(
@BiometricState oldState: Int,
@BiometricState newState: Int
): Boolean = when (newState) {
STATE_PENDING_CONFIRMATION -> true
STATE_AUTHENTICATED -> false
- else -> super.shouldAnimateForTransition(oldState, newState)
+ else -> super.shouldAnimateIconViewForTransition(oldState, newState)
}
@RawRes
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index b962cc4..436f9df 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -104,12 +104,14 @@
iconView.frame = 0
iconViewOverlay.frame = 0
- if (shouldAnimateForTransition(lastState, newState)) {
- iconView.playAnimation()
- iconViewOverlay.playAnimation()
- } else if (lastState == STATE_IDLE && newState == STATE_AUTHENTICATING_ANIMATING_IN) {
+ if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
}
+
+ if (shouldAnimateIconViewOverlayForTransition(lastState, newState)) {
+ iconViewOverlay.playAnimation()
+ }
+
LottieColorUtils.applyDynamicColors(context, iconView)
LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
}
@@ -127,7 +129,7 @@
}
iconView.frame = 0
- if (shouldAnimateForTransition(lastState, newState)) {
+ if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
}
LottieColorUtils.applyDynamicColors(context, iconView)
@@ -160,7 +162,20 @@
return if (id != null) context.getString(id) else null
}
- protected open fun shouldAnimateForTransition(
+ protected open fun shouldAnimateIconViewForTransition(
+ @BiometricState oldState: Int,
+ @BiometricState newState: Int
+ ) = when (newState) {
+ STATE_HELP,
+ STATE_ERROR -> true
+ STATE_AUTHENTICATING_ANIMATING_IN,
+ STATE_AUTHENTICATING ->
+ oldState == STATE_ERROR || oldState == STATE_HELP || oldState == STATE_IDLE
+ STATE_AUTHENTICATED -> true
+ else -> false
+ }
+
+ protected open fun shouldAnimateIconViewOverlayForTransition(
@BiometricState oldState: Int,
@BiometricState newState: Int
) = when (newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index cee2282..63a1b76 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -32,6 +32,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -41,7 +42,6 @@
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 59f68f7..9cbc64e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -32,6 +32,7 @@
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.log.SessionTracker
+import com.android.systemui.media.dialog.MediaOutputSwitcherDialogUI
import com.android.systemui.media.RingtonePlayer
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
@@ -218,6 +219,12 @@
@ClassKey(ToastUI::class)
abstract fun bindToastUI(service: ToastUI): CoreStartable
+ /** Inject into MediaOutputSwitcherDialogUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(MediaOutputSwitcherDialogUI::class)
+ abstract fun MediaOutputSwitcherDialogUI(sysui: MediaOutputSwitcherDialogUI): CoreStartable
+
/** Inject into VolumeUI. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index c73387b..72c7cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -119,6 +119,7 @@
private boolean mListening;
private boolean mListeningTouchScreenSensors;
private boolean mListeningProxSensors;
+ private boolean mListeningAodOnlySensors;
private boolean mUdfpsEnrolled;
@DevicePostureController.DevicePostureInt
@@ -187,7 +188,8 @@
dozeParameters.getPulseOnSigMotion(),
DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
false /* touchCoords */,
- false /* touchscreen */),
+ false /* touchscreen */
+ ),
new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PICK_UP_GESTURE,
@@ -198,14 +200,17 @@
false /* touchscreen */,
false /* ignoresSetting */,
false /* requires prox */,
- true /* immediatelyReRegister */),
+ true /* immediatelyReRegister */,
+ false /* requiresAod */
+ ),
new TriggerSensor(
findSensor(config.doubleTapSensorType()),
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
true /* configured */,
DozeLog.REASON_SENSOR_DOUBLE_TAP,
dozeParameters.doubleTapReportsTouchCoordinates(),
- true /* touchscreen */),
+ true /* touchscreen */
+ ),
new TriggerSensor(
findSensors(config.tapSensorTypeMapping()),
Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
@@ -217,7 +222,9 @@
false /* ignoresSetting */,
dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */,
true /* immediatelyReRegister */,
- mDevicePosture),
+ mDevicePosture,
+ false
+ ),
new TriggerSensor(
findSensor(config.longPressSensorType()),
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
@@ -228,7 +235,9 @@
true /* touchscreen */,
false /* ignoresSetting */,
dozeParameters.longPressUsesProx() /* requiresProx */,
- true /* immediatelyReRegister */),
+ true /* immediatelyReRegister */,
+ false /* requiresAod */
+ ),
new TriggerSensor(
findSensor(config.udfpsLongPressSensorType()),
"doze_pulse_on_auth",
@@ -239,7 +248,9 @@
true /* touchscreen */,
false /* ignoresSetting */,
dozeParameters.longPressUsesProx(),
- false /* immediatelyReRegister */),
+ false /* immediatelyReRegister */,
+ true /* requiresAod */
+ ),
new PluginSensor(
new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
@@ -247,7 +258,8 @@
&& mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT),
DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE,
false /* reports touch coordinates */,
- false /* touchscreen */),
+ false /* touchscreen */
+ ),
new PluginSensor(
new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
@@ -255,7 +267,8 @@
DozeLog.PULSE_REASON_SENSOR_WAKE_REACH,
false /* reports touch coordinates */,
false /* touchscreen */,
- mConfig.getWakeLockScreenDebounce()),
+ mConfig.getWakeLockScreenDebounce()
+ ),
new TriggerSensor(
findSensor(config.quickPickupSensorType()),
Settings.Secure.DOZE_QUICK_PICKUP_GESTURE,
@@ -266,7 +279,9 @@
false /* requiresTouchscreen */,
false /* ignoresSetting */,
false /* requiresProx */,
- true /* immediatelyReRegister */),
+ true /* immediatelyReRegister */,
+ false /* requiresAod */
+ ),
};
setProxListening(false); // Don't immediately start listening when we register.
mProximitySensor.register(
@@ -360,29 +375,36 @@
/**
* If sensors should be registered and sending signals.
*/
- public void setListening(boolean listen, boolean includeTouchScreenSensors) {
- if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors) {
+ public void setListening(boolean listen, boolean includeTouchScreenSensors,
+ boolean includeAodOnlySensors) {
+ if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors
+ && mListeningAodOnlySensors == includeAodOnlySensors) {
return;
}
mListening = listen;
mListeningTouchScreenSensors = includeTouchScreenSensors;
+ mListeningAodOnlySensors = includeAodOnlySensors;
updateListening();
}
/**
* If sensors should be registered and sending signals.
*/
- public void setListening(boolean listen, boolean includeTouchScreenSensors,
- boolean lowPowerStateOrOff) {
+ public void setListeningWithPowerState(boolean listen, boolean includeTouchScreenSensors,
+ boolean includeAodRequiringSensors, boolean lowPowerStateOrOff) {
final boolean shouldRegisterProxSensors =
!mSelectivelyRegisterProxSensors || lowPowerStateOrOff;
- if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors
- && mListeningProxSensors == shouldRegisterProxSensors) {
+ if (mListening == listen
+ && mListeningTouchScreenSensors == includeTouchScreenSensors
+ && mListeningProxSensors == shouldRegisterProxSensors
+ && mListeningAodOnlySensors == includeAodRequiringSensors
+ ) {
return;
}
mListening = listen;
mListeningTouchScreenSensors = includeTouchScreenSensors;
mListeningProxSensors = shouldRegisterProxSensors;
+ mListeningAodOnlySensors = includeAodRequiringSensors;
updateListening();
}
@@ -394,7 +416,8 @@
for (TriggerSensor s : mTriggerSensors) {
boolean listen = mListening
&& (!s.mRequiresTouchscreen || mListeningTouchScreenSensors)
- && (!s.mRequiresProx || mListeningProxSensors);
+ && (!s.mRequiresProx || mListeningProxSensors)
+ && (!s.mRequiresAod || mListeningAodOnlySensors);
s.setListening(listen);
if (listen) {
anyListening = true;
@@ -502,6 +525,9 @@
private final boolean mRequiresTouchscreen;
private final boolean mRequiresProx;
+ // Whether the sensor should only register if the device is in AOD
+ private final boolean mRequiresAod;
+
// Whether to immediately re-register this sensor after the sensor is triggered.
// If false, the sensor registration will be updated on the next AOD state transition.
private final boolean mImmediatelyReRegister;
@@ -530,7 +556,8 @@
requiresTouchscreen,
false /* ignoresSetting */,
false /* requiresProx */,
- true /* immediatelyReRegister */
+ true /* immediatelyReRegister */,
+ false
);
}
@@ -544,7 +571,8 @@
boolean requiresTouchscreen,
boolean ignoresSetting,
boolean requiresProx,
- boolean immediatelyReRegister
+ boolean immediatelyReRegister,
+ boolean requiresAod
) {
this(
new Sensor[]{ sensor },
@@ -557,7 +585,8 @@
ignoresSetting,
requiresProx,
immediatelyReRegister,
- DevicePostureController.DEVICE_POSTURE_UNKNOWN
+ DevicePostureController.DEVICE_POSTURE_UNKNOWN,
+ requiresAod
);
}
@@ -572,7 +601,8 @@
boolean ignoresSetting,
boolean requiresProx,
boolean immediatelyReRegister,
- @DevicePostureController.DevicePostureInt int posture
+ @DevicePostureController.DevicePostureInt int posture,
+ boolean requiresAod
) {
mSensors = sensors;
mSetting = setting;
@@ -583,6 +613,7 @@
mRequiresTouchscreen = requiresTouchscreen;
mIgnoresSetting = ignoresSetting;
mRequiresProx = requiresProx;
+ mRequiresAod = requiresAod;
mPosture = posture;
mImmediatelyReRegister = immediatelyReRegister;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b95c3f3..b709608 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -111,6 +111,7 @@
private boolean mWantProxSensor;
private boolean mWantTouchScreenSensors;
private boolean mWantSensors;
+ private boolean mInAod;
private final UserTracker.Callback mUserChangedCallback =
new UserTracker.Callback() {
@@ -460,12 +461,19 @@
mDozeSensors.requestTemporaryDisable();
break;
case DOZE:
- case DOZE_AOD:
mAodInterruptRunnable = null;
- mWantProxSensor = newState != DozeMachine.State.DOZE;
+ mWantProxSensor = false;
mWantSensors = true;
mWantTouchScreenSensors = true;
- if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
+ mInAod = false;
+ break;
+ case DOZE_AOD:
+ mAodInterruptRunnable = null;
+ mWantProxSensor = true;
+ mWantSensors = true;
+ mWantTouchScreenSensors = true;
+ mInAod = true;
+ if (!sWakeDisplaySensorState) {
onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE);
}
break;
@@ -491,7 +499,7 @@
break;
default:
}
- mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors);
+ mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors, mInAod);
}
private void registerCallbacks() {
@@ -510,11 +518,12 @@
private void stopListeningToAllTriggers() {
unregisterCallbacks();
- mDozeSensors.setListening(false, false);
+ mDozeSensors.setListening(false, false, false);
mDozeSensors.setProxListening(false);
mWantSensors = false;
mWantProxSensor = false;
mWantTouchScreenSensors = false;
+ mInAod = false;
}
@Override
@@ -523,7 +532,8 @@
final boolean lowPowerStateOrOff = state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND || state == Display.STATE_OFF;
mDozeSensors.setProxListening(mWantProxSensor && lowPowerStateOrOff);
- mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors, lowPowerStateOrOff);
+ mDozeSensors.setListeningWithPowerState(mWantSensors, mWantTouchScreenSensors,
+ mInAod, lowPowerStateOrOff);
if (mAodInterruptRunnable != null && state == Display.STATE_ON) {
mAodInterruptRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 3106173..33c8379 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -38,6 +38,7 @@
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -85,8 +86,9 @@
private boolean mBouncerAnimating;
- private final KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback =
- new KeyguardBouncer.PrimaryBouncerExpansionCallback() {
+ private final PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback =
+ new PrimaryBouncerExpansionCallback() {
@Override
public void onStartingToShow() {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f60f9a1..c45c8e7 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -77,12 +77,6 @@
// TODO(b/254512731): Tracking Bug
@JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade")
- // TODO(b/259558771): Tracking Bug
- val STABILITY_INDEX_FIX = releasedFlag(114, "stability_index_fix")
-
- // TODO(b/259559750): Tracking Bug
- val SEMI_STABLE_SORT = releasedFlag(115, "semi_stable_sort")
-
@JvmField val USE_ROUNDNESS_SOURCETYPES = releasedFlag(116, "use_roundness_sourcetype")
// TODO(b/259217907)
@@ -411,6 +405,17 @@
val WM_DESKTOP_WINDOWING_2 =
sysPropBooleanFlag(1112, "persist.wm.debug.desktop_mode_2", default = false)
+ // TODO(b/254513207): Tracking Bug to delete
+ @Keep
+ @JvmField
+ val WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES =
+ unreleasedFlag(
+ 1113,
+ name = "screen_record_enterprise_policies",
+ namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ teamfood = false
+ )
+
// 1200 - predictive back
@Keep
@JvmField
@@ -475,8 +480,7 @@
// 1800 - shade container
@JvmField
- val LEAVE_SHADE_OPEN_FOR_BUGREPORT =
- unreleasedFlag(1800, "leave_shade_open_for_bugreport", teamfood = true)
+ val LEAVE_SHADE_OPEN_FOR_BUGREPORT = releasedFlag(1800, "leave_shade_open_for_bugreport")
// 1900
@JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
@@ -520,6 +524,11 @@
@JvmField
val OUTPUT_SWITCHER_DEVICE_STATUS = unreleasedFlag(2502, "output_switcher_device_status")
+ // TODO(b/20911786): Tracking Bug
+ @JvmField
+ val OUTPUT_SWITCHER_SHOW_API_ENABLED =
+ unreleasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true)
+
// TODO(b259590361): Tracking bug
val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
index c5e49c6..3099a49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
@@ -18,27 +18,29 @@
import android.view.View
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.phone.KeyguardBouncer
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.util.ListenerSet
import javax.inject.Inject
/** Interactor to add and remove callbacks for the bouncer. */
@SysUISingleton
class PrimaryBouncerCallbackInteractor @Inject constructor() {
- private var resetCallbacks = ListenerSet<KeyguardBouncer.KeyguardResetCallback>()
- private var expansionCallbacks = ArrayList<KeyguardBouncer.PrimaryBouncerExpansionCallback>()
+ private var resetCallbacks = ListenerSet<KeyguardResetCallback>()
+ private var expansionCallbacks = ArrayList<PrimaryBouncerExpansionCallback>()
+
/** Add a KeyguardResetCallback. */
- fun addKeyguardResetCallback(callback: KeyguardBouncer.KeyguardResetCallback) {
+ fun addKeyguardResetCallback(callback: KeyguardResetCallback) {
resetCallbacks.addIfAbsent(callback)
}
/** Remove a KeyguardResetCallback. */
- fun removeKeyguardResetCallback(callback: KeyguardBouncer.KeyguardResetCallback) {
+ fun removeKeyguardResetCallback(callback: KeyguardResetCallback) {
resetCallbacks.remove(callback)
}
/** Adds a callback to listen to bouncer expansion updates. */
- fun addBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) {
+ fun addBouncerExpansionCallback(callback: PrimaryBouncerExpansionCallback) {
if (!expansionCallbacks.contains(callback)) {
expansionCallbacks.add(callback)
}
@@ -48,7 +50,7 @@
* Removes a previously added callback. If the callback was never added, this method does
* nothing.
*/
- fun removeBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) {
+ fun removeBouncerExpansionCallback(callback: PrimaryBouncerExpansionCallback) {
expansionCallbacks.remove(callback)
}
@@ -99,4 +101,40 @@
callback.onKeyguardReset()
}
}
+
+ /** Callback updated when the primary bouncer's show and hide states change. */
+ interface PrimaryBouncerExpansionCallback {
+ /**
+ * Invoked when the bouncer expansion reaches [EXPANSION_VISIBLE]. This is NOT called each
+ * time the bouncer is shown, but rather only when the fully shown amount has changed based
+ * on the panel expansion. The bouncer's visibility can still change when the expansion
+ * amount hasn't changed. See [PrimaryBouncerInteractor.isFullyShowing] for the checks for
+ * the bouncer showing state.
+ */
+ fun onFullyShown() {}
+
+ /** Invoked when the bouncer is starting to transition to a hidden state. */
+ fun onStartingToHide() {}
+
+ /** Invoked when the bouncer is starting to transition to a visible state. */
+ fun onStartingToShow() {}
+
+ /** Invoked when the bouncer expansion reaches [EXPANSION_HIDDEN]. */
+ fun onFullyHidden() {}
+
+ /**
+ * From 0f [EXPANSION_VISIBLE] when fully visible to 1f [EXPANSION_HIDDEN] when fully hidden
+ */
+ fun onExpansionChanged(bouncerHideAmount: Float) {}
+
+ /**
+ * Invoked when visibility of KeyguardBouncer has changed. Note the bouncer expansion can be
+ * [EXPANSION_VISIBLE], but the view's visibility can be [View.INVISIBLE].
+ */
+ fun onVisibilityChanged(isVisible: Boolean) {}
+ }
+
+ interface KeyguardResetCallback {
+ fun onKeyguardReset()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index ceb4845..a692ad7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -18,6 +18,7 @@
import android.app.ActivityOptions
import android.content.Intent
import android.content.res.Configuration
+import android.content.res.Resources
import android.media.projection.IMediaProjection
import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
import android.os.Binder
@@ -27,6 +28,7 @@
import android.os.UserHandle
import android.view.ViewGroup
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider
import com.android.internal.app.ChooserActivity
import com.android.internal.app.ResolverListController
import com.android.internal.app.chooser.NotSelectableTargetInfo
@@ -59,16 +61,12 @@
private lateinit var configurationController: ConfigurationController
private lateinit var controller: MediaProjectionAppSelectorController
private lateinit var recentsViewController: MediaProjectionRecentsViewController
+ private lateinit var component: MediaProjectionAppSelectorComponent
override fun getLayoutResource() = R.layout.media_projection_app_selector
public override fun onCreate(bundle: Bundle?) {
- val component =
- componentFactory.create(
- activity = this,
- view = this,
- resultHandler = this
- )
+ component = componentFactory.create(activity = this, view = this, resultHandler = this)
// Create a separate configuration controller for this activity as the configuration
// might be different from the global one
@@ -76,11 +74,12 @@
controller = component.controller
recentsViewController = component.recentsViewController
- val queryIntent = Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
- intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
+ intent.configureChooserIntent(
+ resources,
+ component.hostUserHandle,
+ component.personalProfileUserHandle
+ )
- val title = getString(R.string.media_projection_permission_app_selector_title)
- intent.putExtra(Intent.EXTRA_TITLE, title)
super.onCreate(bundle)
controller.init()
}
@@ -183,6 +182,13 @@
override fun shouldShowContentPreview() = true
+ override fun shouldShowContentPreviewWhenEmpty(): Boolean = true
+
+ override fun createMyUserIdProvider(): MyUserIdProvider =
+ object : MyUserIdProvider() {
+ override fun getMyUserId(): Int = component.hostUserHandle.identifier
+ }
+
override fun createContentPreviewView(parent: ViewGroup): ViewGroup =
recentsViewController.createView(parent)
@@ -193,6 +199,34 @@
* instance through activity result.
*/
const val EXTRA_CAPTURE_REGION_RESULT_RECEIVER = "capture_region_result_receiver"
+
+ /** UID of the app that originally launched the media projection flow (host app user) */
+ const val EXTRA_HOST_APP_USER_HANDLE = "launched_from_user_handle"
const val KEY_CAPTURE_TARGET = "capture_region"
+
+ /** Set up intent for the [ChooserActivity] */
+ private fun Intent.configureChooserIntent(
+ resources: Resources,
+ hostUserHandle: UserHandle,
+ personalProfileUserHandle: UserHandle
+ ) {
+ // Specify the query intent to show icons for all apps on the chooser screen
+ val queryIntent =
+ Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
+ putExtra(Intent.EXTRA_INTENT, queryIntent)
+
+ // Update the title of the chooser
+ val title = resources.getString(R.string.media_projection_permission_app_selector_title)
+ putExtra(Intent.EXTRA_TITLE, title)
+
+ // Select host app's profile tab by default
+ val selectedProfile =
+ if (hostUserHandle == personalProfileUserHandle) {
+ PROFILE_PERSONAL
+ } else {
+ PROFILE_WORK
+ }
+ putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index bfa67a8..d830fc4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -22,6 +22,7 @@
import static com.android.systemui.screenrecord.ScreenShareOptionKt.SINGLE_APP;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
@@ -35,6 +36,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.text.BidiFormatter;
import android.text.SpannableString;
import android.text.TextPaint;
@@ -208,8 +210,14 @@
final Intent intent = new Intent(this, MediaProjectionAppSelectorActivity.class);
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
projection.asBinder());
+ intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE,
+ UserHandle.getUserHandleForUid(getLaunchedFromUid()));
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- startActivity(intent);
+
+ // Start activity from the current foreground user to avoid creating a separate
+ // SystemUI process without access to recent tasks because it won't have
+ // WM Shell running inside.
+ startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
}
} catch (RemoteException e) {
Log.e(TAG, "Error granting projection permission", e);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
new file mode 100644
index 0000000..e35575b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
@@ -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.
+ */
+
+package com.android.systemui.media.dialog;
+
+import android.annotation.MainThread;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.statusbar.CommandQueue;
+
+import javax.inject.Inject;
+
+/** Controls display of media output switcher. */
+@SysUISingleton
+public class MediaOutputSwitcherDialogUI implements CoreStartable, CommandQueue.Callbacks {
+
+ private static final String TAG = "MediaOutputSwitcherDialogUI";
+
+ private final CommandQueue mCommandQueue;
+ private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private final FeatureFlags mFeatureFlags;
+
+ @Inject
+ public MediaOutputSwitcherDialogUI(
+ Context context,
+ CommandQueue commandQueue,
+ MediaOutputDialogFactory mediaOutputDialogFactory,
+ FeatureFlags featureFlags) {
+ mCommandQueue = commandQueue;
+ mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ mFeatureFlags = featureFlags;
+ }
+
+ @Override
+ public void start() {
+ if (mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_SHOW_API_ENABLED)) {
+ mCommandQueue.addCallback(this);
+ } else {
+ Log.w(TAG, "Show media output switcher is not enabled.");
+ }
+ }
+
+ @Override
+ @MainThread
+ public void showMediaOutputSwitcher(String packageName) {
+ if (!TextUtils.isEmpty(packageName)) {
+ mMediaOutputDialogFactory.create(packageName, false, null);
+ } else {
+ Log.e(TAG, "Unable to launch media output dialog. Package name is empty.");
+ }
+ }
+}
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 6c41caa..1d86343 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -19,9 +19,11 @@
import android.app.Activity
import android.content.ComponentName
import android.content.Context
+import android.os.UserHandle
import com.android.launcher3.icons.IconFactory
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.ActivityTaskManagerThumbnailLoader
import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader
@@ -30,6 +32,8 @@
import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.Binds
@@ -39,6 +43,7 @@
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
@@ -46,6 +51,12 @@
@Qualifier @Retention(AnnotationRetention.BINARY) annotation class MediaProjectionAppSelector
+@Qualifier @Retention(AnnotationRetention.BINARY) annotation class HostUserHandle
+
+@Qualifier @Retention(AnnotationRetention.BINARY) annotation class PersonalProfile
+
+@Qualifier @Retention(AnnotationRetention.BINARY) annotation class WorkProfile
+
@Retention(AnnotationRetention.RUNTIME) @Scope annotation class MediaProjectionAppSelectorScope
@Module(subcomponents = [MediaProjectionAppSelectorComponent::class])
@@ -83,7 +94,7 @@
@MediaProjectionAppSelector
@MediaProjectionAppSelectorScope
fun provideAppSelectorComponentName(context: Context): ComponentName =
- ComponentName(context, MediaProjectionAppSelectorActivity::class.java)
+ ComponentName(context, MediaProjectionAppSelectorActivity::class.java)
@Provides
@MediaProjectionAppSelector
@@ -93,9 +104,32 @@
): ConfigurationController = ConfigurationControllerImpl(activity)
@Provides
- fun bindIconFactory(
- context: Context
- ): IconFactory = IconFactory.obtain(context)
+ @PersonalProfile
+ @MediaProjectionAppSelectorScope
+ fun personalUserHandle(activityManagerWrapper: ActivityManagerWrapper): UserHandle {
+ // Current foreground user is the 'personal' profile
+ return UserHandle.of(activityManagerWrapper.currentUserId)
+ }
+
+ @Provides
+ @WorkProfile
+ @MediaProjectionAppSelectorScope
+ fun workProfileUserHandle(userTracker: UserTracker): UserHandle? =
+ userTracker.userProfiles.find { it.isManagedProfile }?.userHandle
+
+ @Provides
+ @HostUserHandle
+ @MediaProjectionAppSelectorScope
+ fun hostUserHandle(activity: MediaProjectionAppSelectorActivity): UserHandle {
+ val extras =
+ 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")
+ }
+
+ @Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context)
@Provides
@MediaProjectionAppSelector
@@ -124,6 +158,8 @@
val controller: MediaProjectionAppSelectorController
val recentsViewController: MediaProjectionRecentsViewController
+ @get:HostUserHandle val hostUserHandle: UserHandle
+ @get:PersonalProfile val personalProfileUserHandle: UserHandle
@MediaProjectionAppSelector val configurationController: ConfigurationController
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index d744a40b..52c7ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -17,24 +17,36 @@
package com.android.systemui.mediaprojection.appselector
import android.content.ComponentName
+import android.os.UserHandle
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
-import javax.inject.Inject
@MediaProjectionAppSelectorScope
-class MediaProjectionAppSelectorController @Inject constructor(
+class MediaProjectionAppSelectorController
+@Inject
+constructor(
private val recentTaskListProvider: RecentTaskListProvider,
private val view: MediaProjectionAppSelectorView,
+ private val flags: FeatureFlags,
+ @HostUserHandle private val hostUserHandle: UserHandle,
@MediaProjectionAppSelector private val scope: CoroutineScope,
@MediaProjectionAppSelector private val appSelectorComponentName: ComponentName
) {
fun init() {
scope.launch {
- val tasks = recentTaskListProvider.loadRecentTasks().sortTasks()
+ val recentTasks = recentTaskListProvider.loadRecentTasks()
+
+ val tasks = recentTasks
+ .filterDevicePolicyRestrictedTasks()
+ .sortedTasks()
+
view.bind(tasks)
}
}
@@ -43,9 +55,20 @@
scope.cancel()
}
- private fun List<RecentTask>.sortTasks(): List<RecentTask> =
- sortedBy {
- // Show normal tasks first and only then tasks with opened app selector
- it.topActivityComponent == appSelectorComponentName
+ /**
+ * Removes all recent tasks that are different from the profile of the host app to avoid any
+ * cross-profile sharing
+ */
+ private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> =
+ if (flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
+ // TODO(b/263950746): filter tasks based on the enterprise policies
+ this
+ } else {
+ filter { UserHandle.of(it.userId) == hostUserHandle }
}
+
+ private fun List<RecentTask>.sortedTasks(): List<RecentTask> = sortedBy {
+ // Show normal tasks first and only then tasks with opened app selector
+ it.topActivityComponent == appSelectorComponentName
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
index cd994b8..41e2286 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
@@ -17,11 +17,12 @@
package com.android.systemui.mediaprojection.appselector.data
import android.annotation.ColorInt
+import android.annotation.UserIdInt
import android.content.ComponentName
data class RecentTask(
val taskId: Int,
- val userId: Int,
+ @UserIdInt val userId: Int,
val topActivityComponent: ComponentName?,
val baseIntentComponent: ComponentName?,
@ColorInt val colorBackground: Int?
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 245a55d..3e6eb05 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -525,6 +525,15 @@
}
private void updateIsEnabled() {
+ try {
+ Trace.beginSection("EdgeBackGestureHandler#updateIsEnabled");
+ updateIsEnabledTraced();
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private void updateIsEnabledTraced() {
boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
if (isEnabled == mIsEnabled) {
return;
@@ -611,14 +620,16 @@
}
private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
- if (mEdgeBackPlugin != null) {
- mEdgeBackPlugin.onDestroy();
+ try {
+ Trace.beginSection("setEdgeBackPlugin");
+ mEdgeBackPlugin = edgeBackPlugin;
+ mEdgeBackPlugin.setBackCallback(mBackCallback);
+ mEdgeBackPlugin.setMotionEventsHandler(mMotionEventsHandler);
+ mEdgeBackPlugin.setLayoutParams(createLayoutParams());
+ updateDisplaySize();
+ } finally {
+ Trace.endSection();
}
- mEdgeBackPlugin = edgeBackPlugin;
- mEdgeBackPlugin.setBackCallback(mBackCallback);
- mEdgeBackPlugin.setMotionEventsHandler(mMotionEventsHandler);
- mEdgeBackPlugin.setLayoutParams(createLayoutParams());
- updateDisplaySize();
}
public boolean isHandlingGestures() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index 44b18ec..68e3dcd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -23,6 +23,7 @@
import android.os.Handler
import android.os.Looper
import android.os.ResultReceiver
+import android.os.UserHandle
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
@@ -77,6 +78,14 @@
MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
CaptureTargetResultReceiver()
)
+
+ // Send SystemUI's user handle as the host app user handle because SystemUI
+ // is the 'host app' (the app that receives screen capture data)
+ intent.putExtra(
+ MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE,
+ UserHandle.of(UserHandle.myUserId())
+ )
+
val animationController = dialogLaunchAnimator.createActivityLaunchController(v!!)
if (animationController == null) {
dismiss()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 964d0b2..fd31e49 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -715,7 +715,7 @@
updatePanelExpansionAndVisibility();
};
private final Runnable mMaybeHideExpandedRunnable = () -> {
- if (getExpansionFraction() == 0.0f) {
+ if (getExpandedFraction() == 0.0f) {
postToView(mHideExpandedRunnable);
}
};
@@ -5451,10 +5451,6 @@
InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
}
- private float getExpansionFraction() {
- return mExpandedFraction;
- }
-
private ShadeExpansionStateManager getShadeExpansionStateManager() {
return mShadeExpansionStateManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 04adaae..6e4ed7b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -43,12 +43,14 @@
import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Pair;
import android.util.SparseArray;
@@ -166,6 +168,7 @@
private static final int MSG_SHOW_REAR_DISPLAY_DIALOG = 69 << MSG_SHIFT;
private static final int MSG_GO_TO_FULLSCREEN_FROM_SPLIT = 70 << MSG_SHIFT;
private static final int MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP = 71 << MSG_SHIFT;
+ private static final int MSG_SHOW_MEDIA_OUTPUT_SWITCHER = 72 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -490,6 +493,11 @@
* @see IStatusBar#enterStageSplitFromRunningApp
*/
default void enterStageSplitFromRunningApp(boolean leftOrTop) {}
+
+ /**
+ * @see IStatusBar#showMediaOutputSwitcher
+ */
+ default void showMediaOutputSwitcher(String packageName) {}
}
public CommandQueue(Context context) {
@@ -1259,6 +1267,19 @@
}
@Override
+ public void showMediaOutputSwitcher(String packageName) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Call only allowed from system server.");
+ }
+ synchronized (mLock) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = packageName;
+ mHandler.obtainMessage(MSG_SHOW_MEDIA_OUTPUT_SWITCHER, args).sendToTarget();
+ }
+ }
+
+ @Override
public void requestAddTile(
@NonNull ComponentName componentName,
@NonNull CharSequence appName,
@@ -1774,6 +1795,13 @@
mCallbacks.get(i).enterStageSplitFromRunningApp((Boolean) msg.obj);
}
break;
+ case MSG_SHOW_MEDIA_OUTPUT_SWITCHER:
+ args = (SomeArgs) msg.obj;
+ String clientPackageName = (String) args.arg1;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).showMediaOutputSwitcher(clientPackageName);
+ }
+ break;
}
}
}
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 3072c81..05a9a42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -35,14 +35,6 @@
fun fsiOnDNDUpdate(): Boolean = featureFlags.isEnabled(Flags.FSI_ON_DND_UPDATE)
- val isStabilityIndexFixEnabled: Boolean by lazy {
- featureFlags.isEnabled(Flags.STABILITY_INDEX_FIX)
- }
-
- val isSemiStableSortEnabled: Boolean by lazy {
- featureFlags.isEnabled(Flags.SEMI_STABLE_SORT)
- }
-
val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy {
featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
index 84ab0d1..b5fce41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
@@ -98,13 +98,11 @@
* This can happen if the entry is removed from a group that was broken up or if the entry was
* filtered out during any of the filtering steps.
*/
- fun detach(includingStableIndex: Boolean) {
+ fun detach() {
parent = null
section = null
promoter = null
- if (includingStableIndex) {
- stableIndex = -1
- }
+ stableIndex = -1
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 65a21a4..4065b98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -965,8 +965,7 @@
* filtered out during any of the filtering steps.
*/
private void annulAddition(ListEntry entry) {
- // NOTE(b/241229236): Don't clear stableIndex until we fix stability fragility
- entry.getAttachState().detach(/* includingStableIndex= */ mFlags.isSemiStableSortEnabled());
+ entry.getAttachState().detach();
}
private void assignSections() {
@@ -986,50 +985,10 @@
private void sortListAndGroups() {
Trace.beginSection("ShadeListBuilder.sortListAndGroups");
- if (mFlags.isSemiStableSortEnabled()) {
- sortWithSemiStableSort();
- } else {
- sortWithLegacyStability();
- }
+ sortWithSemiStableSort();
Trace.endSection();
}
- private void sortWithLegacyStability() {
- // Sort all groups and the top level list
- for (ListEntry entry : mNotifList) {
- if (entry instanceof GroupEntry) {
- GroupEntry parent = (GroupEntry) entry;
- parent.sortChildren(mGroupChildrenComparator);
- }
- }
- mNotifList.sort(mTopLevelComparator);
- assignIndexes(mNotifList);
-
- // Check for suppressed order changes
- if (!getStabilityManager().isEveryChangeAllowed()) {
- mForceReorderable = true;
- boolean isSorted = isShadeSortedLegacy();
- mForceReorderable = false;
- if (!isSorted) {
- getStabilityManager().onEntryReorderSuppressed();
- }
- }
- }
-
- private boolean isShadeSortedLegacy() {
- if (!isSorted(mNotifList, mTopLevelComparator)) {
- return false;
- }
- for (ListEntry entry : mNotifList) {
- if (entry instanceof GroupEntry) {
- if (!isSorted(((GroupEntry) entry).getChildren(), mGroupChildrenComparator)) {
- return false;
- }
- }
- }
- return true;
- }
-
private void sortWithSemiStableSort() {
// Sort each group's children
boolean allSorted = true;
@@ -1100,29 +1059,16 @@
sectionMemberIndex = 0;
currentSection = section;
}
- if (mFlags.isStabilityIndexFixEnabled()) {
- entry.getAttachState().setStableIndex(sectionMemberIndex++);
- if (entry instanceof GroupEntry) {
- final GroupEntry parent = (GroupEntry) entry;
- final NotificationEntry summary = parent.getSummary();
- if (summary != null) {
- summary.getAttachState().setStableIndex(sectionMemberIndex++);
- }
- for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setStableIndex(sectionMemberIndex++);
- }
+ entry.getAttachState().setStableIndex(sectionMemberIndex++);
+ if (entry instanceof GroupEntry) {
+ final GroupEntry parent = (GroupEntry) entry;
+ final NotificationEntry summary = parent.getSummary();
+ if (summary != null) {
+ summary.getAttachState().setStableIndex(sectionMemberIndex++);
}
- } else {
- // This old implementation uses the same index number for the group as the first
- // child, and fails to assign an index to the summary. Remove once tested.
- entry.getAttachState().setStableIndex(sectionMemberIndex);
- if (entry instanceof GroupEntry) {
- final GroupEntry parent = (GroupEntry) entry;
- for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setStableIndex(sectionMemberIndex++);
- }
+ for (NotificationEntry child : parent.getChildren()) {
+ child.getAttachState().setStableIndex(sectionMemberIndex++);
}
- sectionMemberIndex++;
}
}
}
@@ -1272,11 +1218,6 @@
o2.getSectionIndex());
if (cmp != 0) return cmp;
- cmp = mFlags.isSemiStableSortEnabled() ? 0 : Integer.compare(
- getStableOrderIndex(o1),
- getStableOrderIndex(o2));
- if (cmp != 0) return cmp;
-
NotifComparator sectionComparator = getSectionComparator(o1, o2);
if (sectionComparator != null) {
cmp = sectionComparator.compare(o1, o2);
@@ -1301,12 +1242,7 @@
private final Comparator<NotificationEntry> mGroupChildrenComparator = (o1, o2) -> {
- int cmp = mFlags.isSemiStableSortEnabled() ? 0 : Integer.compare(
- getStableOrderIndex(o1),
- getStableOrderIndex(o2));
- if (cmp != 0) return cmp;
-
- cmp = Integer.compare(
+ int cmp = Integer.compare(
o1.getRepresentativeEntry().getRanking().getRank(),
o2.getRepresentativeEntry().getRanking().getRank());
if (cmp != 0) return cmp;
@@ -1317,25 +1253,6 @@
return cmp;
};
- /**
- * A flag that is set to true when we want to run the comparators as if all reordering is
- * allowed. This is used to check if the list is "out of order" after the sort is complete.
- */
- private boolean mForceReorderable = false;
-
- private int getStableOrderIndex(ListEntry entry) {
- if (mForceReorderable) {
- // this is used to determine if the list is correctly sorted
- return -1;
- }
- if (getStabilityManager().isEntryReorderingAllowed(entry)) {
- // let the stability manager constrain or allow reordering
- return -1;
- }
- // NOTE(b/241229236): Can't use cleared section index until we fix stability fragility
- return entry.getPreviousAttachState().getStableIndex();
- }
-
@Nullable
private Integer getStableOrderRank(ListEntry entry) {
if (getStabilityManager().isEntryReorderingAllowed(entry)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 4b56594..ec08bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -295,6 +295,7 @@
private final Context mContext;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final DeviceStateManager mDeviceStateManager;
private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
private float mTransitionToFullShadeProgress = 0f;
private NotificationListContainer mNotifListContainer;
@@ -862,8 +863,7 @@
mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
id -> onLaunchTransitionTimeout());
- deviceStateManager.registerCallback(mMainExecutor,
- new FoldStateListener(mContext, this::onFoldedStateChanged));
+ mDeviceStateManager = deviceStateManager;
wiredChargingRippleController.registerCallbacks();
mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy;
@@ -1052,6 +1052,8 @@
}
});
+ registerCallbacks();
+
mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
mPluginManager.addPluginListener(
@@ -1107,6 +1109,14 @@
}
@VisibleForTesting
+ /** Registers listeners/callbacks with external dependencies. */
+ void registerCallbacks() {
+ //TODO(b/264502026) move the rest of the listeners here.
+ mDeviceStateManager.registerCallback(mMainExecutor,
+ new FoldStateListener(mContext, this::onFoldedStateChanged));
+ }
+
+ @VisibleForTesting
void initShadeVisibilityListener() {
mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f08de85..d318759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -46,6 +46,8 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.KeyguardResetCallback;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ListenerSet;
@@ -658,56 +660,6 @@
mExpansionCallbacks.remove(callback);
}
- /**
- * Callback updated when the primary bouncer's show and hide states change.
- */
- public interface PrimaryBouncerExpansionCallback {
- /**
- * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}.
- * This is NOT called each time the bouncer is shown, but rather only when the fully
- * shown amount has changed based on the panel expansion. The bouncer's visibility
- * can still change when the expansion amount hasn't changed.
- * See {@link KeyguardBouncer#isShowing()} for the checks for the bouncer showing state.
- */
- default void onFullyShown() {
- }
-
- /**
- * Invoked when the bouncer is starting to transition to a hidden state.
- */
- default void onStartingToHide() {
- }
-
- /**
- * Invoked when the bouncer is starting to transition to a visible state.
- */
- default void onStartingToShow() {
- }
-
- /**
- * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_HIDDEN}.
- */
- default void onFullyHidden() {
- }
-
- /**
- * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
- * to 1f {@link KeyguardBouncer#EXPANSION_HIDDEN} when fully hidden
- */
- default void onExpansionChanged(float bouncerHideAmount) {}
-
- /**
- * Invoked when visibility of KeyguardBouncer has changed.
- * Note the bouncer expansion can be {@link KeyguardBouncer#EXPANSION_VISIBLE}, but the
- * view's visibility can be {@link View.INVISIBLE}.
- */
- default void onVisibilityChanged(boolean isVisible) {}
- }
-
- public interface KeyguardResetCallback {
- void onKeyguardReset();
- }
-
/** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
public static class Factory {
private final Context mContext;
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 003b020..001da6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -62,6 +62,7 @@
import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -78,7 +79,6 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.unfold.FoldAodAnimationController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 97b4c2c..e0d156a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -18,6 +18,7 @@
import android.provider.Settings
import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
@@ -37,6 +38,15 @@
/** Observable for the subscriptionId of the current mobile data connection */
val activeMobileDataSubscriptionId: StateFlow<Int>
+ /**
+ * Observable event for when the active data sim switches but the group stays the same. E.g.,
+ * CBRS switching would trigger this
+ */
+ val activeSubChangedInGroupEvent: Flow<Unit>
+
+ /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
+ val defaultDataSubId: StateFlow<Int>
+
/** The current connectivity status for the default mobile network connection */
val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 0c8593d6..b939856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -124,6 +124,9 @@
realRepository.activeMobileDataSubscriptionId.value
)
+ override val activeSubChangedInGroupEvent: Flow<Unit> =
+ activeRepo.flatMapLatest { it.activeSubChangedInGroupEvent }
+
override val defaultDataSubRatConfig: StateFlow<MobileMappings.Config> =
activeRepo
.flatMapLatest { it.defaultDataSubRatConfig }
@@ -139,6 +142,11 @@
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
+ override val defaultDataSubId: StateFlow<Int> =
+ activeRepo
+ .flatMapLatest { it.defaultDataSubId }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.defaultDataSubId.value)
+
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
activeRepo
.flatMapLatest { it.defaultMobileNetworkConnectivity }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 22aca0a..1088345 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -48,6 +48,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -120,6 +121,9 @@
subscriptions.value.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID
)
+ // TODO(b/261029387): consider adding a demo command for this
+ override val activeSubChangedInGroupEvent: Flow<Unit> = flowOf()
+
/** Demo mode doesn't currently support modifications to the mobile mappings */
override val defaultDataSubRatConfig =
MutableStateFlow(MobileMappings.Config.readConfig(context))
@@ -148,8 +152,12 @@
private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
+ // TODO(b/261029387): add a command for this value
+ override val defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+
// TODO(b/261029387): not yet supported
- override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
+ override val defaultMobileNetworkConnectivity =
+ MutableStateFlow(MobileConnectivityModel(isConnected = true, isValidated = true))
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
val current = connectionRepoCache[subId]?.repo
@@ -229,6 +237,9 @@
val connection = getRepoForSubId(subId)
connectionRepoCache[subId]?.lastMobileState = state
+ // TODO(b/261029387): until we have a command, use the most recent subId
+ defaultDataSubId.value = subId
+
// This is always true here, because we split out disabled states at the data-source level
connection.dataEnabled.value = true
connection.networkName.value = NetworkNameModel.Derived(state.name)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 4472e09..510482d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -35,6 +35,7 @@
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
+import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.R
@@ -52,6 +53,7 @@
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.util.kotlin.pairwiseBy
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -60,9 +62,12 @@
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
@@ -159,10 +164,24 @@
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
- private val defaultDataSubIdChangedEvent =
+ private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+
+ override val defaultDataSubId: StateFlow<Int> =
broadcastDispatcher
- .broadcastFlow(IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED))
+ .broadcastFlow(
+ IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ ) { intent, _ ->
+ intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ }
+ .distinctUntilChanged()
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
+ .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ SubscriptionManager.getDefaultDataSubscriptionId()
+ )
private val carrierConfigChangedEvent =
broadcastDispatcher
@@ -170,7 +189,7 @@
.logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
override val defaultDataSubRatConfig: StateFlow<Config> =
- merge(defaultDataSubIdChangedEvent, carrierConfigChangedEvent)
+ merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
.logInputChange(logger, "defaultDataSubRatConfig")
@@ -258,6 +277,35 @@
.logInputChange(logger, "defaultMobileNetworkConnectivity")
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
+ /**
+ * Flow that tracks the active mobile data subscriptions. Emits `true` whenever the active data
+ * subscription Id changes but the subscription group remains the same. In these cases, we want
+ * to retain the previous subscription's validation status for up to 2s to avoid flickering the
+ * icon.
+ *
+ * TODO(b/265164432): we should probably expose all change events, not just same group
+ */
+ @SuppressLint("MissingPermission")
+ override val activeSubChangedInGroupEvent =
+ flow {
+ activeMobileDataSubscriptionId.pairwiseBy { prevVal: Int, newVal: Int ->
+ if (!defaultMobileNetworkConnectivity.value.isValidated) {
+ return@pairwiseBy
+ }
+ val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevVal)
+ val nextSub = subscriptionManager.getActiveSubscriptionInfo(newVal)
+
+ if (prevSub == null || nextSub == null) {
+ return@pairwiseBy
+ }
+
+ if (prevSub.groupUuid != null && prevSub.groupUuid == nextSub.groupUuid) {
+ emit(Unit)
+ }
+ }
+ }
+ .flowOn(bgDispatcher)
+
private fun isValidSubId(subId: Int): Boolean {
subscriptions.value.forEach {
if (it.subscriptionId == subId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 003df24..9cdff96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -18,9 +18,11 @@
import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons.NOT_DEFAULT_DATA
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
@@ -41,12 +43,29 @@
/** The current mobile data activity */
val activity: Flow<DataActivityModel>
+ /**
+ * This bit is meant to be `true` if and only if the default network capabilities (see
+ * [android.net.ConnectivityManager.registerDefaultNetworkCallback]) result in a network that
+ * has the [android.net.NetworkCapabilities.TRANSPORT_CELLULAR] represented.
+ *
+ * Note that this differs from [isDataConnected], which is tracked by telephony and has to do
+ * with the state of using this mobile connection for data as opposed to just voice. It is
+ * possible for a mobile subscription to be connected but not be in a connected data state, and
+ * thus we wouldn't want to show the network type icon.
+ */
+ val isConnected: Flow<Boolean>
+
+ /**
+ * True when telephony tells us that the data state is CONNECTED. See
+ * [android.telephony.TelephonyCallback.DataConnectionStateListener] for more details. We
+ * consider this connection to be serving data, and thus want to show a network type icon, when
+ * data is connected. Other data connection states would typically cause us not to show the icon
+ */
+ val isDataConnected: StateFlow<Boolean>
+
/** Only true if mobile is the default transport but is not validated, otherwise false */
val isDefaultConnectionFailed: StateFlow<Boolean>
- /** True when telephony tells us that the data state is CONNECTED */
- val isDataConnected: StateFlow<Boolean>
-
/** True if we consider this connection to be in service, i.e. can make calls */
val isInService: StateFlow<Boolean>
@@ -100,8 +119,10 @@
defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
override val alwaysShowDataRatIcon: StateFlow<Boolean>,
override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+ defaultMobileConnectivity: StateFlow<MobileConnectivityModel>,
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
+ defaultDataSubId: StateFlow<Int>,
override val isDefaultConnectionFailed: StateFlow<Boolean>,
connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
@@ -111,8 +132,19 @@
override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
+ override val isConnected: Flow<Boolean> = defaultMobileConnectivity.mapLatest { it.isConnected }
+
override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
+ private val isDefault =
+ defaultDataSubId
+ .mapLatest { connectionRepository.subId == it }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ connectionRepository.subId == defaultDataSubId.value
+ )
+
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
override val networkName =
@@ -137,7 +169,12 @@
connectionInfo,
defaultMobileIconMapping,
defaultMobileIconGroup,
- ) { info, mapping, defaultGroup ->
+ isDefault,
+ ) { info, mapping, defaultGroup, isDefault ->
+ if (!isDefault) {
+ return@combine NOT_DEFAULT_DATA
+ }
+
when (info.resolvedNetworkType) {
is ResolvedNetworkType.CarrierMergedNetworkType ->
info.resolvedNetworkType.iconGroupOverride
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 83da1dd..9ae38e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -23,6 +23,7 @@
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -31,14 +32,17 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
/**
* Business layer logic for the set of mobile subscription icons.
@@ -62,6 +66,17 @@
/** True if the CDMA level should be preferred over the primary level. */
val alwaysUseCdmaLevel: StateFlow<Boolean>
+ /** Tracks the subscriptionId set as the default for data connections */
+ val defaultDataSubId: StateFlow<Int>
+
+ /**
+ * The connectivity of the default mobile network. Note that this can differ from what is
+ * reported from [MobileConnectionsRepository] in some cases. E.g., when the active subscription
+ * changes but the groupUuid remains the same, we keep the old validation information for 2
+ * seconds to avoid icon flickering.
+ */
+ val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>
+
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
/** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
@@ -154,6 +169,48 @@
}
}
+ override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
+
+ /**
+ * Copied from the old pipeline. We maintain a 2s period of time where we will keep the
+ * validated bit from the old active network (A) while data is changing to the new one (B).
+ *
+ * This condition only applies if
+ * 1. A and B are in the same subscription group (e.c. for CBRS data switching) and
+ * 2. A was validated before the switch
+ *
+ * The goal of this is to minimize the flickering in the UI of the cellular indicator
+ */
+ private val forcingCellularValidation =
+ mobileConnectionsRepo.activeSubChangedInGroupEvent
+ .filter { mobileConnectionsRepo.defaultMobileNetworkConnectivity.value.isValidated }
+ .transformLatest {
+ emit(true)
+ delay(2000)
+ emit(false)
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
+ combine(
+ mobileConnectionsRepo.defaultMobileNetworkConnectivity,
+ forcingCellularValidation,
+ ) { networkConnectivity, forceValidation ->
+ return@combine if (forceValidation) {
+ MobileConnectivityModel(
+ isValidated = true,
+ isConnected = networkConnectivity.isConnected
+ )
+ } else {
+ networkConnectivity
+ }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ mobileConnectionsRepo.defaultMobileNetworkConnectivity.value
+ )
+
/**
* Mapping from network type to [MobileIconGroup] using the config generated for the default
* subscription Id. This mapping is the same for every subscription.
@@ -207,8 +264,10 @@
activeDataConnectionHasDataEnabled,
alwaysShowDataRatIcon,
alwaysUseCdmaLevel,
+ defaultMobileNetworkConnectivity,
defaultMobileIconMapping,
defaultMobileIconGroup,
+ defaultDataSubId,
isDefaultConnectionFailed,
mobileConnectionsRepo.getRepoForSubId(subId),
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index a2117c7..5e935616 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -102,24 +102,29 @@
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}
+ private val showNetworkTypeIcon: Flow<Boolean> =
+ combine(
+ iconInteractor.isDataConnected,
+ iconInteractor.isDataEnabled,
+ iconInteractor.isDefaultConnectionFailed,
+ iconInteractor.alwaysShowDataRatIcon,
+ iconInteractor.isConnected,
+ ) { dataConnected, dataEnabled, failedConnection, alwaysShow, connected ->
+ alwaysShow || (dataConnected && dataEnabled && !failedConnection && connected)
+ }
+
override val networkTypeIcon: Flow<Icon?> =
combine(
iconInteractor.networkTypeIconGroup,
- iconInteractor.isDataConnected,
- iconInteractor.isDataEnabled,
- iconInteractor.isDefaultConnectionFailed,
- iconInteractor.alwaysShowDataRatIcon,
- ) { networkTypeIconGroup, dataConnected, dataEnabled, failedConnection, alwaysShow ->
+ showNetworkTypeIcon,
+ ) { networkTypeIconGroup, shouldShow ->
val desc =
if (networkTypeIconGroup.dataContentDescription != 0)
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
else null
val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
return@combine when {
- alwaysShow -> icon
- !dataConnected -> null
- !dataEnabled -> null
- failedConnection -> null
+ !shouldShow -> null
else -> icon
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
index 7726d09..8214822 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
@@ -3,26 +3,43 @@
import android.os.SystemProperties
import android.os.VibrationEffect
import android.os.Vibrator
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
import javax.inject.Inject
-/**
- * Class that plays a haptics effect during unfolding a foldable device
- */
+/** Class that plays a haptics effect during unfolding a foldable device */
@SysUIUnfoldScope
class UnfoldHapticsPlayer
@Inject
constructor(
unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
+ foldProvider: FoldProvider,
+ @Main private val mainExecutor: Executor,
private val vibrator: Vibrator?
) : TransitionProgressListener {
+ private var isFirstAnimationAfterUnfold = false
+
init {
if (vibrator != null) {
// We don't need to remove the callback because we should listen to it
// the whole time when SystemUI process is alive
unfoldTransitionProgressProvider.addCallback(this)
}
+
+ foldProvider.registerCallback(
+ object : FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ if (isFolded) {
+ isFirstAnimationAfterUnfold = true
+ }
+ }
+ },
+ mainExecutor
+ )
}
private var lastTransitionProgress = TRANSITION_PROGRESS_FULL_OPEN
@@ -36,6 +53,13 @@
}
override fun onTransitionFinishing() {
+ // Run haptics only when unfolding the device (first animation after unfolding)
+ if (!isFirstAnimationAfterUnfold) {
+ return
+ }
+
+ isFirstAnimationAfterUnfold = false
+
// Run haptics only if the animation is long enough to notice
if (lastTransitionProgress < TRANSITION_NOTICEABLE_THRESHOLD) {
playHaptics()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 813eeeb..7715f7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -32,9 +32,9 @@
import androidx.test.filters.SmallTest;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,9 +46,9 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
- private @Captor ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback>
+ private @Captor ArgumentCaptor<PrimaryBouncerExpansionCallback>
mBouncerExpansionCallbackCaptor;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
@Override
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index cefba62..b6da649 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -146,7 +146,7 @@
@Test
public void testSensorDebounce() {
- mDozeSensors.setListening(true, true);
+ mDozeSensors.setListening(true, true, true);
mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
mTestableLooper.processAllMessages();
@@ -164,7 +164,7 @@
@Test
public void testSetListening_firstTrue_registerSettingsObserver() {
verify(mSensorManager, never()).registerListener(any(), any(Sensor.class), anyInt());
- mDozeSensors.setListening(true, true);
+ mDozeSensors.setListening(true, true, true);
verify(mTriggerSensor).registerSettingsObserver(any(ContentObserver.class));
}
@@ -172,8 +172,8 @@
@Test
public void testSetListening_twiceTrue_onlyRegisterSettingsObserverOnce() {
verify(mSensorManager, never()).registerListener(any(), any(Sensor.class), anyInt());
- mDozeSensors.setListening(true, true);
- mDozeSensors.setListening(true, true);
+ mDozeSensors.setListening(true, true, true);
+ mDozeSensors.setListening(true, true, true);
verify(mTriggerSensor, times(1)).registerSettingsObserver(any(ContentObserver.class));
}
@@ -198,7 +198,7 @@
assertFalse(mSensorTap.mRequested);
// WHEN we're now in a low powered state
- dozeSensors.setListening(true, true, true);
+ dozeSensors.setListeningWithPowerState(true, true, true, true);
// THEN the tap sensor is registered
assertTrue(mSensorTap.mRequested);
@@ -209,12 +209,12 @@
// GIVEN doze sensors enabled
when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
- // GIVEN a trigger sensor
+ // GIVEN a trigger sensor that's enabled by settings
Sensor mockSensor = mock(Sensor.class);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorWithSettingEnabled(
mockSensor,
- /* settingEnabled */ true,
- /* requiresTouchScreen */ true);
+ /* settingEnabled */ true
+ );
when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
.thenReturn(true);
@@ -230,12 +230,12 @@
// GIVEN doze sensors enabled
when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
- // GIVEN a trigger sensor
+ // GIVEN a trigger sensor that's not enabled by settings
Sensor mockSensor = mock(Sensor.class);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorWithSettingEnabled(
mockSensor,
- /* settingEnabled*/ false,
- /* requiresTouchScreen */ true);
+ /* settingEnabled*/ false
+ );
when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
.thenReturn(true);
@@ -251,12 +251,12 @@
// GIVEN doze sensors enabled
when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
- // GIVEN a trigger sensor that's
+ // GIVEN a trigger sensor that's not enabled by settings
Sensor mockSensor = mock(Sensor.class);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorWithSettingEnabled(
mockSensor,
- /* settingEnabled*/ false,
- /* requiresTouchScreen */ true);
+ /* settingEnabled*/ false
+ );
when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
.thenReturn(true);
@@ -266,7 +266,7 @@
// WHEN ignoreSetting is called
triggerSensor.ignoreSetting(true);
- // THEN the sensor is registered
+ // THEN the sensor is still registered since the setting is ignore
assertTrue(triggerSensor.mRegistered);
}
@@ -277,10 +277,10 @@
// GIVEN a trigger sensor
Sensor mockSensor = mock(Sensor.class);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorWithSettingEnabled(
mockSensor,
- /* settingEnabled*/ true,
- /* requiresTouchScreen */ true);
+ /* settingEnabled*/ true
+ );
when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
.thenReturn(true);
@@ -297,7 +297,7 @@
// GIVEN doze sensor that supports postures
Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorForPosture(
new Sensor[] {
null /* unknown */,
closedSensor,
@@ -318,7 +318,7 @@
// GIVEN doze sensor that supports postures
Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorForPosture(
new Sensor[] {
null /* unknown */,
closedSensor,
@@ -347,7 +347,7 @@
// GIVEN doze sensor that supports postures
Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorForPosture(
new Sensor[] {
null /* unknown */,
closedSensor,
@@ -402,7 +402,7 @@
public void testUdfpsEnrollmentChanged() throws Exception {
// GIVEN a UDFPS_LONG_PRESS trigger sensor that's not configured
Sensor mockSensor = mock(Sensor.class);
- TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensorForPosture(
mockSensor,
REASON_SENSOR_UDFPS_LONG_PRESS,
/* configured */ false);
@@ -411,7 +411,7 @@
.thenReturn(true);
// WHEN listening state is set to TRUE
- mDozeSensors.setListening(true, true);
+ mDozeSensors.setListening(true, true, true);
// THEN mRegistered is still false b/c !mConfigured
assertFalse(triggerSensor.mConfigured);
@@ -441,6 +441,35 @@
}
@Test
+ public void aodOnlySensor_onlyRegisteredWhenAodSensorsIncluded() {
+ // GIVEN doze sensors enabled
+ when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+ // GIVEN a trigger sensor that requires aod
+ Sensor mockSensor = mock(Sensor.class);
+ TriggerSensor aodOnlyTriggerSensor = mDozeSensors.createDozeSensorRequiringAod(mockSensor);
+ when(mSensorManager.requestTriggerSensor(eq(aodOnlyTriggerSensor), eq(mockSensor)))
+ .thenReturn(true);
+ mDozeSensors.addSensor(aodOnlyTriggerSensor);
+
+ // WHEN aod only sensors aren't included
+ mDozeSensors.setListening(/* listen */ true, /* includeTouchScreenSensors */true,
+ /* includeAodOnlySensors */false);
+
+ // THEN the sensor is not registered or requested
+ assertFalse(aodOnlyTriggerSensor.mRequested);
+ assertFalse(aodOnlyTriggerSensor.mRegistered);
+
+ // WHEN aod only sensors ARE included
+ mDozeSensors.setListening(/* listen */ true, /* includeTouchScreenSensors */true,
+ /* includeAodOnlySensors */true);
+
+ // THEN the sensor is registered and requested
+ assertTrue(aodOnlyTriggerSensor.mRequested);
+ assertTrue(aodOnlyTriggerSensor.mRegistered);
+ }
+
+ @Test
public void liftToWake_defaultSetting_configDefaultFalse() {
// WHEN the default lift to wake gesture setting is false
when(mResources.getBoolean(
@@ -496,8 +525,8 @@
mTriggerSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap};
}
- public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled,
- boolean requiresTouchScreen) {
+ public TriggerSensor createDozeSensorWithSettingEnabled(Sensor sensor,
+ boolean settingEnabled) {
return new TriggerSensor(/* sensor */ sensor,
/* setting name */ "test_setting",
/* settingDefault */ settingEnabled,
@@ -506,11 +535,13 @@
/* reportsTouchCoordinate*/ false,
/* requiresTouchscreen */ false,
/* ignoresSetting */ false,
- requiresTouchScreen,
- /* immediatelyReRegister */ true);
+ /* requiresProx */ false,
+ /* immediatelyReRegister */ true,
+ /* requiresAod */false
+ );
}
- public TriggerSensor createDozeSensor(
+ public TriggerSensor createDozeSensorForPosture(
Sensor sensor,
int pulseReason,
boolean configured
@@ -524,15 +555,35 @@
/* requiresTouchscreen */ false,
/* ignoresSetting */ false,
/* requiresTouchScreen */ false,
- /* immediatelyReRegister*/ true);
+ /* immediatelyReRegister*/ true,
+ false
+ );
}
/**
- * create a doze sensor that supports postures and is enabled
+ * Create a doze sensor that requires Aod
*/
- public TriggerSensor createDozeSensor(Sensor[] sensors, int posture) {
+ public TriggerSensor createDozeSensorRequiringAod(Sensor sensor) {
+ return new TriggerSensor(/* sensor */ sensor,
+ /* setting name */ "aod_requiring_sensor",
+ /* settingDefault */ true,
+ /* configured */ true,
+ /* pulseReason*/ 0,
+ /* reportsTouchCoordinate*/ false,
+ /* requiresTouchscreen */ false,
+ /* ignoresSetting */ false,
+ /* requiresProx */ false,
+ /* immediatelyReRegister */ true,
+ /* requiresAoD */ true
+ );
+ }
+
+ /**
+ * Create a doze sensor that supports postures and is enabled
+ */
+ public TriggerSensor createDozeSensorForPosture(Sensor[] sensors, int posture) {
return new TriggerSensor(/* sensor */ sensors,
- /* setting name */ "test_setting",
+ /* setting name */ "posture_test_setting",
/* settingDefault */ true,
/* configured */ true,
/* pulseReason*/ 0,
@@ -541,7 +592,9 @@
/* ignoresSetting */ true,
/* requiresProx */ false,
/* immediatelyReRegister */ true,
- posture);
+ posture,
+ /* requiresUi */ false
+ );
}
public void addSensor(TriggerSensor sensor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index b66a454..3552399 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -395,6 +395,14 @@
verify(mAuthController).onAodInterrupt(anyInt(), anyInt(), anyFloat(), anyFloat());
}
+
+ @Test
+ public void udfpsLongPress_dozeState_notRegistered() {
+ // GIVEN device is DOZE_AOD_PAUSED
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+ // beverlyt
+ }
+
private void waitForSensorManager() {
mExecutor.runAllReady();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 2799a25..ff883eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -37,9 +37,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
index db9c4e7..fbfeca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
@@ -19,7 +19,6 @@
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.phone.KeyguardBouncer
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,8 +33,10 @@
private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor()
@Mock
private lateinit var mPrimaryBouncerExpansionCallback:
- KeyguardBouncer.PrimaryBouncerExpansionCallback
- @Mock private lateinit var keyguardResetCallback: KeyguardBouncer.KeyguardResetCallback
+ PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ @Mock
+ private lateinit var keyguardResetCallback:
+ PrimaryBouncerCallbackInteractor.KeyguardResetCallback
@Before
fun setup() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 19d2d33..1042ea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -1,12 +1,16 @@
package com.android.systemui.mediaprojection.appselector
import android.content.ComponentName
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
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.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.junit.Test
@@ -21,11 +25,17 @@
private val scope = CoroutineScope(Dispatchers.Unconfined)
private val appSelectorComponentName = ComponentName("com.test", "AppSelector")
+ private val hostUserHandle = UserHandle.of(123)
+ private val otherUserHandle = UserHandle.of(456)
+
private val view: MediaProjectionAppSelectorView = mock()
+ private val featureFlags: FeatureFlags = mock()
private val controller = MediaProjectionAppSelectorController(
taskListProvider,
view,
+ featureFlags,
+ hostUserHandle,
scope,
appSelectorComponentName
)
@@ -98,15 +108,72 @@
)
}
+ @Test
+ fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsOnlyTasksWithHostProfile() {
+ givenEnterprisePoliciesFeatureFlag(enabled = false)
+
+ val tasks = listOf(
+ createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ )
+ taskListProvider.tasks = tasks
+
+ controller.init()
+
+ verify(view).bind(
+ listOf(
+ createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ )
+ )
+ }
+
+ @Test
+ fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesEnabled_bindsAllTasks() {
+ givenEnterprisePoliciesFeatureFlag(enabled = true)
+
+ val tasks = listOf(
+ createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ )
+ taskListProvider.tasks = tasks
+
+ controller.init()
+
+ // TODO(b/233348916) should filter depending on the policies
+ verify(view).bind(
+ listOf(
+ createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ )
+ )
+ }
+
+ private fun givenEnterprisePoliciesFeatureFlag(enabled: Boolean) {
+ whenever(featureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES))
+ .thenReturn(enabled)
+ }
+
private fun createRecentTask(
taskId: Int,
- topActivityComponent: ComponentName? = null
+ topActivityComponent: ComponentName? = null,
+ userId: Int = hostUserHandle.identifier
): RecentTask {
return RecentTask(
taskId = taskId,
topActivityComponent = topActivityComponent,
baseIntentComponent = ComponentName("com", "Test"),
- userId = 0,
+ userId = userId,
colorBackground = 0
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
index 4d89495..3b85dba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
@@ -39,11 +39,10 @@
@Test
public void needReinflate_differentLength() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
Notification.Action action =
createActionBuilder("first", R.drawable.ic_corp_icon, pendingIntent).build();
assertThat(NotificationUiAdjustment.needReinflate(
@@ -54,11 +53,10 @@
@Test
public void needReinflate_differentLabels() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
Notification.Action firstAction =
createActionBuilder("first", R.drawable.ic_corp_icon, pendingIntent).build();
Notification.Action secondAction =
@@ -72,11 +70,10 @@
@Test
public void needReinflate_differentIcons() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
Notification.Action firstAction =
createActionBuilder("same", R.drawable.ic_corp_icon, pendingIntent).build();
Notification.Action secondAction =
@@ -91,14 +88,15 @@
@Test
public void needReinflate_differentPendingIntent() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent firstPendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_VIEW),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
PendingIntent secondPendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_PROCESS_TEXT),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent(Intent.ACTION_PROCESS_TEXT)
+ .setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
Notification.Action firstAction =
createActionBuilder("same", R.drawable.ic_corp_icon, firstPendingIntent)
.build();
@@ -114,11 +112,10 @@
@Test
public void needReinflate_differentChoices() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
RemoteInput firstRemoteInput =
createRemoteInput("same", "same", new CharSequence[] {"first"});
@@ -142,11 +139,10 @@
@Test
public void needReinflate_differentRemoteInputLabel() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
RemoteInput firstRemoteInput =
createRemoteInput("same", "first", new CharSequence[] {"same"});
@@ -170,11 +166,10 @@
@Test
public void needReinflate_negative() {
- // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
RemoteInput firstRemoteInput =
createRemoteInput("same", "same", new CharSequence[] {"same"});
RemoteInput secondRemoteInput =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 09f8a10..a869038 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -39,7 +39,6 @@
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 static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -137,7 +136,6 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(true);
mListBuilder = new ShadeListBuilder(
mDumpManager,
@@ -1998,29 +1996,7 @@
}
@Test
- public void testActiveOrdering_withLegacyStability() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(false);
- assertOrder("ABCDEFG", "ABCDEFG", "ABCDEFG", true); // no change
- assertOrder("ABCDEFG", "ACDEFXBG", "ACDEFXBG", true); // X
- assertOrder("ABCDEFG", "ACDEFBG", "ACDEFBG", true); // no change
- assertOrder("ABCDEFG", "ACDEFBXZG", "ACDEFBXZG", true); // Z and X
- assertOrder("ABCDEFG", "AXCDEZFBG", "AXCDEZFBG", true); // Z and X + gap
- }
-
- @Test
- public void testStableOrdering_withLegacyStability() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(false);
- mStabilityManager.setAllowEntryReordering(false);
- assertOrder("ABCDEFG", "ABCDEFG", "ABCDEFG", true); // no change
- assertOrder("ABCDEFG", "ACDEFXBG", "XABCDEFG", false); // X
- assertOrder("ABCDEFG", "ACDEFBG", "ABCDEFG", false); // no change
- assertOrder("ABCDEFG", "ACDEFBXZG", "XZABCDEFG", false); // Z and X
- assertOrder("ABCDEFG", "AXCDEZFBG", "XZABCDEFG", false); // Z and X + gap
- }
-
- @Test
public void testStableOrdering() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
mStabilityManager.setAllowEntryReordering(false);
// No input or output
assertOrder("", "", "", true);
@@ -2076,7 +2052,6 @@
@Test
public void testActiveOrdering() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
assertOrder("ABCDEFG", "ACDEFXBG", "ACDEFXBG", true); // X
assertOrder("ABCDEFG", "ACDEFBG", "ACDEFBG", true); // no change
assertOrder("ABCDEFG", "ACDEFBXZG", "ACDEFBXZG", true); // Z and X
@@ -2133,7 +2108,6 @@
@Test
public void stableOrderingDisregardedWithSectionChange() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
// GIVEN the first sectioner's packages can be changed from run-to-run
List<String> mutableSectionerPackages = new ArrayList<>();
mutableSectionerPackages.add(PACKAGE_1);
@@ -2229,49 +2203,7 @@
}
@Test
- public void groupRevertingToSummaryDoesNotRetainStablePositionWithLegacyIndexLogic() {
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(false);
-
- // GIVEN a notification group is on screen
- mStabilityManager.setAllowEntryReordering(false);
-
- // WHEN the list is originally built with reordering disabled (and section changes allowed)
- addNotif(0, PACKAGE_1).setRank(2);
- addNotif(1, PACKAGE_1).setRank(3);
- addGroupSummary(2, PACKAGE_1, "group").setRank(4);
- addGroupChild(3, PACKAGE_1, "group").setRank(5);
- addGroupChild(4, PACKAGE_1, "group").setRank(6);
- dispatchBuild();
-
- verifyBuiltList(
- notif(0),
- notif(1),
- group(
- summary(2),
- child(3),
- child(4)
- )
- );
-
- // WHEN the notification summary rank increases and children removed
- setNewRank(notif(2).entry, 1);
- mEntrySet.remove(4);
- mEntrySet.remove(3);
- dispatchBuild();
-
- // VERIFY the summary (incorrectly) moves to the top of the section where it is ranked,
- // despite visual stability being active
- verifyBuiltList(
- notif(2),
- notif(0),
- notif(1)
- );
- }
-
- @Test
public void groupRevertingToSummaryRetainsStablePosition() {
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(true);
-
// GIVEN a notification group is on screen
mStabilityManager.setAllowEntryReordering(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 601771d..58fe2a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -885,7 +885,8 @@
private NotificationEntry createBubble(String groupKey, Integer groupAlert) {
Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder(
- PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.getActivity(mContext, 0,
+ new Intent().setPackage(mContext.getPackageName()),
PendingIntent.FLAG_MUTABLE),
Icon.createWithResource(mContext.getResources(), R.drawable.android))
.build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c8157cc..4c1b219 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -544,6 +544,7 @@
mCentralSurfaces.startKeyguard();
mInitController.executePostInitTasks();
notificationLogger.setUpWithContainer(mNotificationListContainer);
+ mCentralSurfaces.registerCallbacks();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 7ad9cc2..2f49535 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -58,8 +58,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -87,7 +87,7 @@
@Mock
private KeyguardHostViewController mKeyguardHostViewController;
@Mock
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mExpansionCallback;
+ private PrimaryBouncerExpansionCallback mExpansionCallback;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index dea4a7d..1ba0a36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -63,6 +63,7 @@
import com.android.systemui.keyguard.data.BouncerViewDelegate;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -126,7 +127,8 @@
@Mock private OnBackAnimationCallback mBouncerViewDelegateBackCallback;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback;
private FakeKeyguardStateController mKeyguardStateController =
spy(new FakeKeyguardStateController());
@@ -193,8 +195,8 @@
mNotificationContainer,
mBypassController);
mStatusBarKeyguardViewManager.show(null);
- ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
- ArgumentCaptor.forClass(KeyguardBouncer.PrimaryBouncerExpansionCallback.class);
+ ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
+ ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
callbackArgumentCaptor.capture());
mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
index 0605b8d..55ab681 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
@@ -60,6 +60,7 @@
import com.android.systemui.keyguard.data.BouncerViewDelegate;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -126,7 +127,8 @@
@Mock private BouncerViewDelegate mBouncerViewDelegate;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback;
private FakeKeyguardStateController mKeyguardStateController =
spy(new FakeKeyguardStateController());
@@ -141,7 +143,7 @@
MockitoAnnotations.initMocks(this);
when(mKeyguardBouncerFactory.create(
any(ViewGroup.class),
- any(KeyguardBouncer.PrimaryBouncerExpansionCallback.class)))
+ any(PrimaryBouncerExpansionCallback.class)))
.thenReturn(mPrimaryBouncer);
when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
@@ -189,8 +191,8 @@
mNotificationContainer,
mBypassController);
mStatusBarKeyguardViewManager.show(null);
- ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
- ArgumentCaptor.forClass(KeyguardBouncer.PrimaryBouncerExpansionCallback.class);
+ ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
+ ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
verify(mKeyguardBouncerFactory).create(any(ViewGroup.class),
callbackArgumentCaptor.capture());
mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 49d4bdc..0add905e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepository
@@ -56,6 +57,10 @@
private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
+ override val activeSubChangedInGroupEvent: MutableSharedFlow<Unit> = MutableSharedFlow()
+
+ private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+ override val defaultDataSubId = _defaultDataSubId
private val _mobileConnectivity = MutableStateFlow(MobileConnectivityModel())
override val defaultMobileNetworkConnectivity = _mobileConnectivity
@@ -81,6 +86,10 @@
_subscriptions.value = subs
}
+ fun setDefaultDataSubId(id: Int) {
+ _defaultDataSubId.value = id
+ }
+
fun setMobileConnectivity(model: MobileConnectivityModel) {
_mobileConnectivity.value = model
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index 9d16b7fe..f12d113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -90,6 +90,14 @@
}
@Test
+ fun `connectivity - defaults to connected and validated`() =
+ testScope.runTest {
+ val connectivity = underTest.defaultMobileNetworkConnectivity.value
+ assertThat(connectivity.isConnected).isTrue()
+ assertThat(connectivity.isValidated).isTrue()
+ }
+
+ @Test
fun `network event - create new subscription`() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 813b0ed..ae390a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -479,6 +479,35 @@
}
@Test
+ fun testDefaultDataSubId_updatesOnBroadcast() =
+ runBlocking(IMMEDIATE) {
+ var latest: Int? = null
+ val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_2_ID)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_1_ID)
+
+ job.cancel()
+ }
+
+ @Test
fun mobileConnectivity_default() {
assertThat(underTest.defaultMobileNetworkConnectivity.value)
.isEqualTo(MobileConnectivityModel(isConnected = false, isValidated = false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index a29146b..7aeaa48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -40,6 +40,8 @@
)
)
+ override val isConnected = MutableStateFlow(true)
+
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.THREE_G)
override val networkTypeIconGroup = _iconGroup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 1c00646..172755c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -23,6 +23,7 @@
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,6 +60,9 @@
override val alwaysShowDataRatIcon = MutableStateFlow(false)
override val alwaysUseCdmaLevel = MutableStateFlow(false)
+ override val defaultDataSubId = MutableStateFlow(DEFAULT_DATA_SUB_ID)
+
+ override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
@@ -77,6 +81,8 @@
companion object {
val DEFAULT_ICON = TelephonyIcons.G
+ const val DEFAULT_DATA_SUB_ID = 1
+
// Use [MobileMappings] to define some simple definitions
const val THREE_G = NETWORK_TYPE_GSM
const val LTE = NETWORK_TYPE_LTE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index e6be7f1..c42aba5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -61,8 +61,10 @@
mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.alwaysShowDataRatIcon,
mobileIconsInteractor.alwaysUseCdmaLevel,
+ mobileIconsInteractor.defaultMobileNetworkConnectivity,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
+ mobileIconsInteractor.defaultDataSubId,
mobileIconsInteractor.isDefaultConnectionFailed,
connectionRepository,
)
@@ -289,6 +291,30 @@
}
@Test
+ fun `icon group - checks default data`() =
+ runBlocking(IMMEDIATE) {
+ mobileIconsInteractor.defaultDataSubId.value = SUB_1_ID
+ connectionRepository.setConnectionInfo(
+ MobileConnectionModel(
+ resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+ ),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(TelephonyIcons.THREE_G)
+
+ // Default data sub id changes to something else
+ mobileIconsInteractor.defaultDataSubId.value = 123
+ yield()
+
+ assertThat(latest).isEqualTo(TelephonyIcons.NOT_DEFAULT_DATA)
+
+ job.cancel()
+ }
+
+ @Test
fun alwaysShowDataRatIcon_matchesParent() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index b82a584..1b62d5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -31,11 +31,13 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield
import org.junit.After
import org.junit.Before
@@ -43,13 +45,16 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class MobileIconsInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconsInteractor
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
private val userSetupRepository = FakeUserSetupRepository()
private val mobileMappingsProxy = FakeMobileMappingsProxy()
- private val scope = CoroutineScope(IMMEDIATE)
+
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
@@ -73,7 +78,7 @@
connectionsRepository,
carrierConfigTracker,
userSetupRepository,
- scope
+ testScope.backgroundScope,
)
}
@@ -81,7 +86,7 @@
@Test
fun filteredSubscriptions_default() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
@@ -92,7 +97,7 @@
@Test
fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
var latest: List<SubscriptionModel>? = null
@@ -105,7 +110,7 @@
@Test
fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -122,7 +127,7 @@
@Test
fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -139,7 +144,7 @@
@Test
fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -157,7 +162,7 @@
@Test
fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -175,7 +180,7 @@
@Test
fun activeDataConnection_turnedOn() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
CONNECTION_1.setDataEnabled(true)
var latest: Boolean? = null
val job =
@@ -188,7 +193,7 @@
@Test
fun activeDataConnection_turnedOff() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
CONNECTION_1.setDataEnabled(true)
var latest: Boolean? = null
val job =
@@ -204,7 +209,7 @@
@Test
fun activeDataConnection_invalidSubId() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job =
underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
@@ -220,7 +225,7 @@
@Test
fun failedConnection_connected_validated_notFailed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
connectionsRepository.setMobileConnectivity(MobileConnectivityModel(true, true))
@@ -233,7 +238,7 @@
@Test
fun failedConnection_notConnected_notValidated_notFailed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
@@ -247,7 +252,7 @@
@Test
fun failedConnection_connected_notValidated_failed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
@@ -261,7 +266,7 @@
@Test
fun alwaysShowDataRatIcon_configHasTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
@@ -277,7 +282,7 @@
@Test
fun alwaysShowDataRatIcon_configHasFalse() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
@@ -293,7 +298,7 @@
@Test
fun alwaysUseCdmaLevel_configHasTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)
@@ -309,7 +314,7 @@
@Test
fun alwaysUseCdmaLevel_configHasFalse() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)
@@ -323,8 +328,286 @@
job.cancel()
}
+ @Test
+ fun `default mobile connectivity - uses repo value`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ var expected = MobileConnectivityModel(isConnected = true, isValidated = true)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = false, isValidated = true)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = true, isValidated = false)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = false, isValidated = false)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - validated matches previous value`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ // Trigger a data change in the same subscription group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - validated matches previous value - expires after 2s`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ // Trigger a data change in the same subscription group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+ // After 1s, the force validation bit is still present
+ advanceTimeBy(1000)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ // After 2s, the force validation expires
+ advanceTimeBy(1001)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - not validated - uses new value immediately`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = false,
+ )
+ )
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - lose validation - then switch happens - clears forced bit`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ // GIVEN the network starts validated
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+
+ // WHEN a data change happens in the same group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ // WHEN the validation bit is lost
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ // WHEN another data change happens in the same group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ // THEN the forced validation bit is still removed after 2s
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ advanceTimeBy(1000)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ advanceTimeBy(1001)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - while already forcing validation - resets clock`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ advanceTimeBy(1000)
+
+ // WHEN another change in same group event happens
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ // THEN the forced validation remains for exactly 2 more seconds from now
+
+ // 1.500s from second event
+ advanceTimeBy(1500)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ // 2.001s from the second event
+ advanceTimeBy(501)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - not in same group - uses new values`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
private val tableLogBuffer =
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 2a8d42f..a24e29ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -274,6 +274,41 @@
}
@Test
+ fun `network type - alwaysShow - shown when not connected`() =
+ testScope.runTest {
+ interactor.setIconGroup(THREE_G)
+ interactor.isConnected.value = false
+ interactor.alwaysShowDataRatIcon.value = true
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ val expected =
+ Icon.Resource(
+ THREE_G.dataType,
+ ContentDescription.Resource(THREE_G.dataContentDescription)
+ )
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `network type - not shown when not connected`() =
+ testScope.runTest {
+ interactor.setIconGroup(THREE_G)
+ interactor.isDataConnected.value = true
+ interactor.isConnected.value = false
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
fun roaming() =
testScope.runTest {
interactor.isRoaming.value = true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 9764b8c..4aa86c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -197,7 +197,7 @@
public void testPinEntry_logsPeek() {
// Needs full screen intent in order to be pinned
final PendingIntent fullScreenIntent = PendingIntent.getActivity(mContext, 0,
- new Intent(), PendingIntent.FLAG_MUTABLE);
+ new Intent().setPackage(mContext.getPackageName()), PendingIntent.FLAG_MUTABLE);
HeadsUpManager.HeadsUpEntry entryToPin = mHeadsUpManager.new HeadsUpEntry();
entryToPin.setEntry(new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index 5e2fa98..85052e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -574,7 +574,8 @@
private void setupAppGeneratedReplies(
CharSequence[] smartReplies, boolean allowSystemGeneratedReplies) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, TEST_INTENT,
+ PendingIntent.getBroadcast(mContext, 0,
+ TEST_INTENT.setPackage(mContext.getPackageName()),
PendingIntent.FLAG_MUTABLE);
Notification.Action action =
new Notification.Action.Builder(null, "Test Action", pendingIntent).build();
@@ -606,7 +607,8 @@
}
private Notification.Action.Builder createActionBuilder(String actionTitle, Intent intent) {
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ intent.setPackage(mContext.getPackageName()),
PendingIntent.FLAG_MUTABLE);
return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 0cca7b2..391c8ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -140,7 +140,8 @@
private void setTestPendingIntent(RemoteInputViewController controller) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(TEST_ACTION), PendingIntent.FLAG_MUTABLE);
+ new Intent(TEST_ACTION).setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
RemoteInput[] inputs = {input};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index a7ff59c..d9d8b63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -488,7 +488,8 @@
private SmartReplyView.SmartReplies createSmartReplies(CharSequence[] choices,
boolean fromAssistant) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION),
+ PendingIntent.getBroadcast(mContext, 0,
+ new Intent(TEST_ACTION).setPackage(mContext.getPackageName()),
PendingIntent.FLAG_MUTABLE);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build();
return new SmartReplyView.SmartReplies(
@@ -505,7 +506,8 @@
private Notification.Action createAction(String actionTitle) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(TEST_ACTION), PendingIntent.FLAG_MUTABLE);
+ new Intent(TEST_ACTION).setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent).build();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 30c4f97..f4226bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -175,8 +175,10 @@
fold()
underTest.onScreenTurningOn({})
- underTest.onStartedWakingUp()
+ // The body of onScreenTurningOn is executed on fakeExecutor,
+ // run all pending tasks before calling the next method
fakeExecutor.runAllReady()
+ underTest.onStartedWakingUp()
verify(latencyTracker).onActionStart(any())
verify(latencyTracker).onActionCancel(any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt
index c316402..4a28cd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt
@@ -26,6 +26,10 @@
listeners.forEach { it.onTransitionFinished() }
}
+ override fun onTransitionFinishing() {
+ listeners.forEach { it.onTransitionFinishing() }
+ }
+
override fun onTransitionProgress(progress: Float) {
listeners.forEach { it.onTransitionProgress(progress) }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
new file mode 100644
index 0000000..d3fdbd9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.unfold
+
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class UnfoldHapticsPlayerTest : SysuiTestCase() {
+
+ private val progressProvider = TestUnfoldTransitionProvider()
+ private val vibrator: Vibrator = mock()
+ private val testFoldProvider = TestFoldProvider()
+
+ private lateinit var player: UnfoldHapticsPlayer
+
+ @Before
+ fun before() {
+ player = UnfoldHapticsPlayer(progressProvider, testFoldProvider, Runnable::run, vibrator)
+ }
+
+ @Test
+ fun testUnfoldingTransitionFinishingEarly_playsHaptics() {
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ testFoldProvider.onFoldUpdate(isFolded = false)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinishing()
+
+ verify(vibrator).vibrate(any<VibrationEffect>())
+ }
+
+ @Test
+ fun testUnfoldingTransitionFinishingLate_doesNotPlayHaptics() {
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ testFoldProvider.onFoldUpdate(isFolded = false)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.99f)
+ progressProvider.onTransitionFinishing()
+
+ verify(vibrator, never()).vibrate(any<VibrationEffect>())
+ }
+
+ @Test
+ fun testFoldingAfterUnfolding_doesNotPlayHaptics() {
+ // Unfold
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ testFoldProvider.onFoldUpdate(isFolded = false)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinishing()
+ progressProvider.onTransitionFinished()
+ clearInvocations(vibrator)
+
+ // Fold
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinished()
+ testFoldProvider.onFoldUpdate(isFolded = true)
+
+ verify(vibrator, never()).vibrate(any<VibrationEffect>())
+ }
+
+ @Test
+ fun testUnfoldingAfterFoldingAndUnfolding_playsHaptics() {
+ // Unfold
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ testFoldProvider.onFoldUpdate(isFolded = false)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinishing()
+ progressProvider.onTransitionFinished()
+
+ // Fold
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinished()
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ clearInvocations(vibrator)
+
+ // Unfold again
+ testFoldProvider.onFoldUpdate(isFolded = true)
+ testFoldProvider.onFoldUpdate(isFolded = false)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionFinishing()
+ progressProvider.onTransitionFinished()
+
+ verify(vibrator).vibrate(any<VibrationEffect>())
+ }
+
+ private class TestFoldProvider : FoldProvider {
+ private val listeners = arrayListOf<FoldProvider.FoldCallback>()
+
+ override fun registerCallback(callback: FoldProvider.FoldCallback, executor: Executor) {
+ listeners += callback
+ }
+
+ override fun unregisterCallback(callback: FoldProvider.FoldCallback) {
+ listeners -= callback
+ }
+
+ fun onFoldUpdate(isFolded: Boolean) {
+ listeners.forEach { it.onFoldUpdated(isFolded) }
+ }
+ }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 5a868a4..cfb959e 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -22,8 +22,8 @@
import android.os.Handler
import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
-import com.android.systemui.unfold.dagger.UnfoldBackground
import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.RotationChangeProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
@@ -58,7 +58,7 @@
@BindsInstance sensorManager: SensorManager,
@BindsInstance @UnfoldMain handler: Handler,
@BindsInstance @UnfoldMain executor: Executor,
- @BindsInstance @UnfoldBackground backgroundExecutor: Executor,
+ @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
@BindsInstance windowManager: IWindowManager,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index 3fa5469..31616fa 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -16,9 +16,7 @@
package com.android.systemui.unfold
-import android.hardware.SensorManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
-import com.android.systemui.unfold.dagger.UnfoldBackground
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
@@ -34,55 +32,18 @@
import dagger.Module
import dagger.Provides
import java.util.Optional
-import java.util.concurrent.Executor
+import javax.inject.Provider
import javax.inject.Singleton
-@Module
+@Module(includes = [UnfoldSharedInternalModule::class])
class UnfoldSharedModule {
@Provides
@Singleton
- fun unfoldTransitionProgressProvider(
- config: UnfoldTransitionConfig,
- scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory,
- tracingListener: ATraceLoggerTransitionProgressListener,
- foldStateProvider: FoldStateProvider
- ): Optional<UnfoldTransitionProgressProvider> =
- if (!config.isEnabled) {
- Optional.empty()
- } else {
- val baseProgressProvider =
- if (config.isHingeAngleEnabled) {
- PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider)
- } else {
- FixedTimingTransitionProgressProvider(foldStateProvider)
- }
- Optional.of(
- scaleAwareProviderFactory.wrap(baseProgressProvider).apply {
- // Always present callback that logs animation beginning and end.
- addCallback(tracingListener)
- }
- )
- }
-
- @Provides
- @Singleton
fun provideFoldStateProvider(
deviceFoldStateProvider: DeviceFoldStateProvider
): FoldStateProvider = deviceFoldStateProvider
@Provides
- fun hingeAngleProvider(
- config: UnfoldTransitionConfig,
- sensorManager: SensorManager,
- @UnfoldBackground executor: Executor
- ): HingeAngleProvider =
- if (config.isHingeAngleEnabled) {
- HingeSensorAngleProvider(sensorManager, executor)
- } else {
- EmptyHingeAngleProvider
- }
-
- @Provides
@Singleton
fun unfoldKeyguardVisibilityProvider(
impl: UnfoldKeyguardVisibilityManagerImpl
@@ -94,3 +55,51 @@
impl: UnfoldKeyguardVisibilityManagerImpl
): UnfoldKeyguardVisibilityManager = impl
}
+
+/**
+ * Needed as methods inside must be public, but their parameters can be internal (and, a public
+ * method can't have internal parameters). Making the module internal and included in a public one
+ * fixes the issue.
+ */
+@Module
+internal class UnfoldSharedInternalModule {
+ @Provides
+ @Singleton
+ fun unfoldTransitionProgressProvider(
+ config: UnfoldTransitionConfig,
+ scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory,
+ tracingListener: ATraceLoggerTransitionProgressListener,
+ physicsBasedUnfoldTransitionProgressProvider:
+ Provider<PhysicsBasedUnfoldTransitionProgressProvider>,
+ fixedTimingTransitionProgressProvider: Provider<FixedTimingTransitionProgressProvider>,
+ ): Optional<UnfoldTransitionProgressProvider> {
+ if (!config.isEnabled) {
+ return Optional.empty()
+ }
+ val baseProgressProvider =
+ if (config.isHingeAngleEnabled) {
+ physicsBasedUnfoldTransitionProgressProvider.get()
+ } else {
+ fixedTimingTransitionProgressProvider.get()
+ }
+
+ return Optional.of(
+ scaleAwareProviderFactory.wrap(baseProgressProvider).apply {
+ // Always present callback that logs animation beginning and end.
+ addCallback(tracingListener)
+ }
+ )
+ }
+
+ @Provides
+ fun hingeAngleProvider(
+ config: UnfoldTransitionConfig,
+ hingeAngleSensorProvider: Provider<HingeSensorAngleProvider>
+ ): HingeAngleProvider {
+ return if (config.isHingeAngleEnabled) {
+ hingeAngleSensorProvider.get()
+ } else {
+ EmptyHingeAngleProvider
+ }
+ }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index a1ed178..aa93c629 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -37,29 +37,29 @@
* This should **never** be called from sysui, as the object is already provided in that process.
*/
fun createUnfoldSharedComponent(
- context: Context,
- config: UnfoldTransitionConfig,
- screenStatusProvider: ScreenStatusProvider,
- foldProvider: FoldProvider,
- activityTypeProvider: CurrentActivityTypeProvider,
- sensorManager: SensorManager,
- mainHandler: Handler,
- mainExecutor: Executor,
- backgroundExecutor: Executor,
- tracingTagPrefix: String,
- windowManager: IWindowManager,
+ context: Context,
+ config: UnfoldTransitionConfig,
+ screenStatusProvider: ScreenStatusProvider,
+ foldProvider: FoldProvider,
+ activityTypeProvider: CurrentActivityTypeProvider,
+ sensorManager: SensorManager,
+ mainHandler: Handler,
+ mainExecutor: Executor,
+ singleThreadBgExecutor: Executor,
+ tracingTagPrefix: String,
+ windowManager: IWindowManager,
): UnfoldSharedComponent =
- DaggerUnfoldSharedComponent.factory()
- .create(
- context,
- config,
- screenStatusProvider,
- foldProvider,
- activityTypeProvider,
- sensorManager,
- mainHandler,
- mainExecutor,
- backgroundExecutor,
- tracingTagPrefix,
- windowManager,
- )
+ DaggerUnfoldSharedComponent.factory()
+ .create(
+ context,
+ config,
+ screenStatusProvider,
+ foldProvider,
+ activityTypeProvider,
+ sensorManager,
+ mainHandler,
+ mainExecutor,
+ singleThreadBgExecutor,
+ tracingTagPrefix,
+ windowManager,
+ )
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldSingleThreadBg.kt
similarity index 89%
rename from packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldSingleThreadBg.kt
index 6074795..dcac531 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldSingleThreadBg.kt
@@ -18,8 +18,7 @@
/**
* Alternative to [UiBackground] qualifier annotation in unfold module.
+ *
* It is needed as we can't depend on SystemUI code in this module.
*/
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-annotation class UnfoldBackground
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class UnfoldSingleThreadBg
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
index fa59cb4..4622464 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -24,11 +24,13 @@
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import javax.inject.Inject
/** Emits animation progress with fixed timing after unfolding */
-internal class FixedTimingTransitionProgressProvider(
- private val foldStateProvider: FoldStateProvider
-) : UnfoldTransitionProgressProvider, FoldStateProvider.FoldUpdatesListener {
+internal class FixedTimingTransitionProgressProvider
+@Inject
+constructor(private val foldStateProvider: FoldStateProvider) :
+ UnfoldTransitionProgressProvider, FoldStateProvider.FoldUpdatesListener {
private val animatorListener = AnimatorListener()
private val animator =
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 074b1e1..6ffbe5a 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -33,9 +33,10 @@
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
import com.android.systemui.unfold.updates.name
+import javax.inject.Inject
/** Maps fold updates to unfold transition progress using DynamicAnimation. */
-class PhysicsBasedUnfoldTransitionProgressProvider(
+class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
private val foldStateProvider: FoldStateProvider
) : UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 5b45897..97c9ba9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -79,6 +79,7 @@
screenStatusProvider.addCallback(screenListener)
hingeAngleProvider.addCallback(hingeAngleListener)
rotationChangeProvider.addCallback(rotationListener)
+ activityTypeProvider.init()
}
override fun stop() {
@@ -87,6 +88,7 @@
hingeAngleProvider.removeCallback(hingeAngleListener)
hingeAngleProvider.stop()
rotationChangeProvider.removeCallback(rotationListener)
+ activityTypeProvider.uninit()
}
override fun addCallback(listener: FoldUpdatesListener) {
@@ -115,19 +117,17 @@
}
val isClosing = angle < lastHingeAngle
- val closingThreshold = getClosingThreshold()
- val closingThresholdMet = closingThreshold == null || angle < closingThreshold
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING
val screenAvailableEventSent = isUnfoldHandled
if (isClosing // hinge angle should be decreasing since last update
- && closingThresholdMet // hinge angle is below certain threshold
&& !closingEventDispatched // we haven't sent closing event already
&& !isFullyOpened // do not send closing event if we are in fully opened hinge
// angle range as closing threshold could overlap this range
&& screenAvailableEventSent // do not send closing event if we are still in
// the process of turning on the inner display
+ && isClosingThresholdMet(angle) // hinge angle is below certain threshold.
) {
notifyFoldUpdate(FOLD_UPDATE_START_CLOSING)
}
@@ -146,6 +146,11 @@
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
}
+ private fun isClosingThresholdMet(currentAngle: Float) : Boolean {
+ val closingThreshold = getClosingThreshold()
+ return closingThreshold == null || currentAngle < closingThreshold
+ }
+
/**
* Fold animation should be started only after the threshold returned here.
*
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index 577137c..89fb12e 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -20,35 +20,43 @@
import android.hardware.SensorManager
import android.os.Trace
import androidx.core.util.Consumer
+import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
import java.util.concurrent.Executor
+import javax.inject.Inject
-internal class HingeSensorAngleProvider(
+internal class HingeSensorAngleProvider
+@Inject
+constructor(
private val sensorManager: SensorManager,
- private val executor: Executor
-) :
- HingeAngleProvider {
+ @UnfoldSingleThreadBg private val singleThreadBgExecutor: Executor
+) : HingeAngleProvider {
private val sensorListener = HingeAngleSensorListener()
private val listeners: MutableList<Consumer<Float>> = arrayListOf()
var started = false
- override fun start() = executor.execute {
- if (started) return@execute
- Trace.beginSection("HingeSensorAngleProvider#start")
- val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
- sensorManager.registerListener(
- sensorListener,
- sensor,
- SensorManager.SENSOR_DELAY_FASTEST
- )
- Trace.endSection()
- started = true
+ override fun start() {
+ singleThreadBgExecutor.execute {
+ if (started) return@execute
+ Trace.beginSection("HingeSensorAngleProvider#start")
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
+ sensorManager.registerListener(
+ sensorListener,
+ sensor,
+ SensorManager.SENSOR_DELAY_FASTEST
+ )
+ Trace.endSection()
+
+ started = true
+ }
}
- override fun stop() = executor.execute {
- if (!started) return@execute
- sensorManager.unregisterListener(sensorListener)
- started = false
+ override fun stop() {
+ singleThreadBgExecutor.execute {
+ if (!started) return@execute
+ sensorManager.unregisterListener(sensorListener)
+ started = false
+ }
}
override fun removeCallback(listener: Consumer<Float>) {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
index d0e6cdc..34e7c38 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
@@ -16,6 +16,11 @@
interface CurrentActivityTypeProvider {
val isHomeActivity: Boolean?
+
+ /** Starts listening for task updates. */
+ fun init() {}
+ /** Stop listening for task updates. */
+ fun uninit() {}
}
class EmptyCurrentActivityTypeProvider(override val isHomeActivity: Boolean? = null) :
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8c09dcd..dc475f6 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -25,7 +25,6 @@
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
-import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupManagerMonitor;
@@ -723,6 +722,17 @@
}
@Override
+ public void setFrameworkSchedulingEnabledForUser(int userId, boolean isEnabled) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId,
+ "setFrameworkSchedulingEnabledForUser()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.setFrameworkSchedulingEnabled(isEnabled);
+ }
+ }
+
+ @Override
public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
throws RemoteException {
if (isUserReadyForBackup(userId)) {
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 0bb25e3..fe0e1c6 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -45,9 +45,12 @@
private final SparseArray<JobParameters> mParamsForUser = new SparseArray<>();
public static void schedule(int userId, Context ctx, long minDelay,
- BackupManagerConstants constants) {
+ UserBackupManagerService userBackupManagerService) {
+ if (!userBackupManagerService.isFrameworkSchedulingEnabled()) return;
+
JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(getJobIdForUserId(userId), sIdleService);
+ final BackupManagerConstants constants = userBackupManagerService.getConstants();
synchronized (constants) {
builder.setRequiresDeviceIdle(true)
.setRequiredNetworkType(constants.getFullBackupRequiredNetworkType())
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index 058dcae..164bbea 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -64,14 +64,16 @@
@VisibleForTesting
public static final int MAX_JOB_ID = 52418896;
- public static void schedule(int userId, Context ctx, BackupManagerConstants constants) {
- schedule(userId, ctx, 0, constants);
+ public static void schedule(int userId, Context ctx,
+ UserBackupManagerService userBackupManagerService) {
+ schedule(userId, ctx, 0, userBackupManagerService);
}
public static void schedule(int userId, Context ctx, long delay,
- BackupManagerConstants constants) {
+ UserBackupManagerService userBackupManagerService) {
synchronized (KeyValueBackupJob.class) {
- if (sScheduledForUserId.get(userId)) {
+ if (sScheduledForUserId.get(userId)
+ || !userBackupManagerService.isFrameworkSchedulingEnabled()) {
return;
}
@@ -80,6 +82,7 @@
final int networkType;
final boolean needsCharging;
+ final BackupManagerConstants constants = userBackupManagerService.getConstants();
synchronized (constants) {
interval = constants.getKeyValueBackupIntervalMilliseconds();
fuzz = constants.getKeyValueBackupFuzzMilliseconds();
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 6ba01d7..2c8bfeb 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -1958,8 +1958,10 @@
}
// We don't want the backup jobs to kick in any time soon.
// Reschedules them to run in the distant future.
- KeyValueBackupJob.schedule(mUserId, mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants);
- FullBackupJob.schedule(mUserId, mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants);
+ KeyValueBackupJob.schedule(mUserId, mContext, BUSY_BACKOFF_MIN_MILLIS,
+ /* userBackupManagerService */ this);
+ FullBackupJob.schedule(mUserId, mContext, 2 * BUSY_BACKOFF_MIN_MILLIS,
+ /* userBackupManagerService */ this);
} finally {
Binder.restoreCallingIdentity(oldToken);
}
@@ -2088,7 +2090,8 @@
final long interval = mConstants.getFullBackupIntervalMilliseconds();
final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0;
final long latency = Math.max(transportMinLatency, appLatency);
- FullBackupJob.schedule(mUserId, mContext, latency, mConstants);
+ FullBackupJob.schedule(mUserId, mContext, latency,
+ /* userBackupManagerService */ this);
} else {
if (DEBUG_SCHEDULING) {
Slog.i(
@@ -2226,7 +2229,8 @@
addUserIdToLogMessage(
mUserId, "Deferring scheduled full backups in battery saver mode"));
}
- FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval, mConstants);
+ FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval,
+ /* userBackupManagerService */ this);
return false;
}
@@ -2392,7 +2396,8 @@
+ "operation; rescheduling +" + latency));
}
final long deferTime = latency; // pin for the closure
- FullBackupJob.schedule(mUserId, mContext, deferTime, mConstants);
+ FullBackupJob.schedule(mUserId, mContext, deferTime,
+ /* userBackupManagerService */ this);
return false;
}
@@ -2495,7 +2500,8 @@
}
// ...and schedule a backup pass if necessary
- KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserId, mContext,
+ /* userBackupManagerService */ this);
}
// Note: packageName is currently unused, but may be in the future
@@ -2730,7 +2736,8 @@
mUserId, "Not running backup while in battery save mode"));
}
// Try again in several hours.
- KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserId, mContext,
+ /* userBackupManagerService */ this);
} else {
if (DEBUG) {
Slog.v(TAG, addUserIdToLogMessage(mUserId, "Scheduling immediate backup pass"));
@@ -3208,12 +3215,51 @@
}
}
+ synchronized void setFrameworkSchedulingEnabled(boolean isEnabled) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "setFrameworkSchedulingEnabled");
+
+ boolean wasEnabled = isFrameworkSchedulingEnabled();
+ if (wasEnabled == isEnabled) {
+ return;
+ }
+
+ Slog.i(TAG, addUserIdToLogMessage(mUserId,
+ (isEnabled ? "Enabling" : "Disabling") + " backup scheduling"));
+
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ // TODO(b/264889098): Consider at a later point if we should us a sentinel file as
+ // setBackupEnabled.
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_SCHEDULING_ENABLED, isEnabled ? 1 : 0, mUserId);
+
+ if (!isEnabled) {
+ KeyValueBackupJob.cancel(mUserId, mContext);
+ FullBackupJob.cancel(mUserId, mContext);
+ } else {
+ KeyValueBackupJob.schedule(mUserId, mContext, /* userBackupManagerService */ this);
+ scheduleNextFullBackupJob(/* transportMinLatency */ 0);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+
+ synchronized boolean isFrameworkSchedulingEnabled() {
+ // By default scheduling is enabled
+ final int defaultSetting = 1;
+ int isEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_SCHEDULING_ENABLED, defaultSetting, mUserId);
+ return isEnabled == 1;
+ }
+
@VisibleForTesting
void updateStateOnBackupEnabled(boolean wasEnabled, boolean enable) {
synchronized (mQueueLock) {
if (enable && !wasEnabled && mSetupComplete) {
// if we've just been enabled, start scheduling backup passes
- KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserId, mContext, /* userBackupManagerService */ this);
scheduleNextFullBackupJob(0);
} else if (!enable) {
// No longer enabled, so stop running backups
@@ -4127,6 +4173,8 @@
pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
if (mBackupRunning) pw.println("Backup currently running");
pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running");
+ pw.println("Framework scheduling is "
+ + (isFrameworkSchedulingEnabled() ? "enabled" : "disabled"));
pw.println("Last backup pass started: " + mLastBackupPass
+ " (now = " + System.currentTimeMillis() + ')');
pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled(mUserId));
diff --git a/services/backup/java/com/android/server/backup/internal/SetupObserver.java b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
index c5e912e..f399fe9 100644
--- a/services/backup/java/com/android/server/backup/internal/SetupObserver.java
+++ b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
-import android.provider.Settings;
import android.util.Slog;
import com.android.server.backup.KeyValueBackupJob;
@@ -78,7 +77,7 @@
Slog.d(TAG, "Setup complete so starting backups");
}
KeyValueBackupJob.schedule(mUserBackupManagerService.getUserId(), mContext,
- mUserBackupManagerService.getConstants());
+ mUserBackupManagerService);
mUserBackupManagerService.scheduleNextFullBackupJob(0);
}
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index ca92b69..41e8092 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -1246,7 +1246,7 @@
delay = 0;
}
KeyValueBackupJob.schedule(mBackupManagerService.getUserId(),
- mBackupManagerService.getContext(), delay, mBackupManagerService.getConstants());
+ mBackupManagerService.getContext(), delay, mBackupManagerService);
for (String packageName : mOriginalQueue) {
mBackupManagerService.dataChangedImpl(packageName);
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index b04f3c5..e9cd84a 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -268,9 +268,9 @@
@NonNull ResultReceiver resultReceiver) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
- createAssociation(userId, packageName, macAddress,
- request.getDisplayName(), request.getDeviceProfile(),
- request.getAssociatedDevice(), request.isSelfManaged(),
+ createAssociation(userId, packageName, macAddress, request.getDisplayName(),
+ request.getDeviceProfile(), request.getAssociatedDevice(),
+ request.isSelfManaged(),
callback, resultReceiver);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
@@ -287,7 +287,8 @@
final AssociationInfo association = new AssociationInfo(id, userId, packageName,
macAddress, displayName, deviceProfile, associatedDevice, selfManaged,
- /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE);
+ /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE,
+ /* systemDataSyncFlags */ ~0);
if (deviceProfile != null) {
// If the "Device Profile" is specified, make the companion application a holder of the
@@ -315,6 +316,20 @@
// that there are other devices with the same profile, so the role holder won't be removed.
}
+ public void enableSystemDataSync(int associationId, int flags) {
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ AssociationInfo updated = AssociationInfo.builder(association)
+ .setSystemDataSyncFlags(association.getSystemDataSyncFlags() | flags).build();
+ mAssociationStore.updateAssociation(updated);
+ }
+
+ public void disableSystemDataSync(int associationId, int flags) {
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ AssociationInfo updated = AssociationInfo.builder(association)
+ .setSystemDataSyncFlags(association.getSystemDataSyncFlags() & (~flags)).build();
+ mAssociationStore.updateAssociation(updated);
+ }
+
private void addAssociationToStore(@NonNull AssociationInfo association,
@Nullable String deviceProfile) {
Slog.i(TAG, "New CDM association created=" + association);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index d34fc59..b74dfcb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -714,6 +714,18 @@
}
@Override
+ public void enableSystemDataSync(int associationId, int flags) {
+ getAssociationWithCallerChecks(associationId);
+ mAssociationRequestsProcessor.enableSystemDataSync(associationId, flags);
+ }
+
+ @Override
+ public void disableSystemDataSync(int associationId, int flags) {
+ getAssociationWithCallerChecks(associationId);
+ mAssociationRequestsProcessor.disableSystemDataSync(associationId, flags);
+ }
+
+ @Override
public void notifyDeviceAppeared(int associationId) {
if (DEBUG) Log.i(TAG, "notifyDevice_Appeared() id=" + associationId);
@@ -1160,16 +1172,20 @@
}
NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
- if (containsEither(packageInfo.requestedPermissions,
- android.Manifest.permission.USE_DATA_IN_BACKGROUND,
- android.Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
- networkPolicyManager.addUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
- } else {
- networkPolicyManager.removeUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ try {
+ if (containsEither(packageInfo.requestedPermissions,
+ android.Manifest.permission.USE_DATA_IN_BACKGROUND,
+ android.Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
+ networkPolicyManager.addUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ } else {
+ networkPolicyManager.removeUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ }
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, e.getMessage());
}
exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index a57f5a2..b66c193 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -132,7 +132,8 @@
* notify_device_nearby="false"
* revoked="false"
* last_time_connected="1634641160229"
- * time_approved="1634389553216"/>
+ * time_approved="1634389553216"
+ * system_data_sync_flags="-1"/>
*
* <association
* id="3"
@@ -143,7 +144,8 @@
* notify_device_nearby="false"
* revoked="false"
* last_time_connected="1634641160229"
- * time_approved="1634641160229"/>
+ * time_approved="1634641160229"
+ * system_data_sync_flags="-1"/>
* </associations>
*
* <previously-used-ids>
@@ -185,6 +187,7 @@
private static final String XML_ATTR_REVOKED = "revoked";
private static final String XML_ATTR_TIME_APPROVED = "time_approved";
private static final String XML_ATTR_LAST_TIME_CONNECTED = "last_time_connected";
+ private static final String XML_ATTR_SYSTEM_DATA_SYNC_FLAGS = "system_data_sync_flags";
private static final String LEGACY_XML_ATTR_DEVICE = "device";
@@ -429,7 +432,7 @@
out.add(new AssociationInfo(associationId, userId, appPackage,
MacAddress.fromString(deviceAddress), null, profile, null,
/* managedByCompanionApp */ false, notify, /* revoked */ false, timeApproved,
- Long.MAX_VALUE));
+ Long.MAX_VALUE, /* systemDataSyncFlags */ -1));
}
private static void readAssociationsV1(@NonNull TypedXmlPullParser parser,
@@ -462,10 +465,12 @@
final long timeApproved = readLongAttribute(parser, XML_ATTR_TIME_APPROVED, 0L);
final long lastTimeConnected = readLongAttribute(
parser, XML_ATTR_LAST_TIME_CONNECTED, Long.MAX_VALUE);
+ final int systemDataSyncFlags = readIntAttribute(parser,
+ XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, -1);
final AssociationInfo associationInfo = createAssociationInfoNoThrow(associationId, userId,
appPackage, macAddress, displayName, profile, selfManaged, notify, revoked,
- timeApproved, lastTimeConnected);
+ timeApproved, lastTimeConnected, systemDataSyncFlags);
if (associationInfo != null) {
out.add(associationInfo);
}
@@ -523,6 +528,7 @@
writeLongAttribute(serializer, XML_ATTR_TIME_APPROVED, a.getTimeApprovedMs());
writeLongAttribute(
serializer, XML_ATTR_LAST_TIME_CONNECTED, a.getLastTimeConnectedMs());
+ writeIntAttribute(serializer, XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, a.getSystemDataSyncFlags());
serializer.endTag(null, XML_TAG_ASSOCIATION);
}
@@ -561,14 +567,15 @@
private static AssociationInfo createAssociationInfoNoThrow(int associationId,
@UserIdInt int userId, @NonNull String appPackage, @Nullable MacAddress macAddress,
@Nullable CharSequence displayName, @Nullable String profile, boolean selfManaged,
- boolean notify, boolean revoked, long timeApproved, long lastTimeConnected) {
+ boolean notify, boolean revoked, long timeApproved, long lastTimeConnected,
+ int systemDataSyncFlags) {
AssociationInfo associationInfo = null;
try {
// We do not persist AssociatedDevice, which means that AssociationInfo retrieved from
// datastore is not guaranteed to be identical to the one from initial association.
associationInfo = new AssociationInfo(associationId, userId, appPackage, macAddress,
displayName, profile, null, selfManaged, notify, revoked,
- timeApproved, lastTimeConnected);
+ timeApproved, lastTimeConnected, systemDataSyncFlags);
} catch (Exception e) {
if (DEBUG) Log.w(TAG, "Could not create AssociationInfo", e);
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 274370e..b67e627 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -227,8 +227,8 @@
# ---------------------------
# NetworkStatsService.java
# ---------------------------
-51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
-51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51100 netstats_mobile_sample (xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51101 netstats_wifi_sample (xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
# ---------------------------
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9bedbd0..4e5ce88 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1000,6 +1000,10 @@
@Override
public void notifySubscriptionInfoChanged() {
if (VDBG) log("notifySubscriptionInfoChanged:");
+ if (!checkNotifyPermission("notifySubscriptionInfoChanged()")) {
+ return;
+ }
+
synchronized (mRecords) {
if (!mHasNotifySubscriptionInfoChangedOccurred) {
log("notifySubscriptionInfoChanged: first invocation mRecords.size="
@@ -1026,6 +1030,10 @@
@Override
public void notifyOpportunisticSubscriptionInfoChanged() {
if (VDBG) log("notifyOpptSubscriptionInfoChanged:");
+ if (!checkNotifyPermission("notifyOpportunisticSubscriptionInfoChanged()")) {
+ return;
+ }
+
synchronized (mRecords) {
if (!mHasNotifyOpportunisticSubscriptionInfoChangedOccurred) {
log("notifyOpptSubscriptionInfoChanged: first invocation mRecords.size="
@@ -3968,66 +3976,6 @@
}
}
- /**
- * Returns a string representation of the radio technology (network type)
- * currently in use on the device.
- * @param type for which network type is returned
- * @return the name of the radio technology
- *
- */
- private String getNetworkTypeName(@Annotation.NetworkType int type) {
- switch (type) {
- case TelephonyManager.NETWORK_TYPE_GPRS:
- return "GPRS";
- case TelephonyManager.NETWORK_TYPE_EDGE:
- return "EDGE";
- case TelephonyManager.NETWORK_TYPE_UMTS:
- return "UMTS";
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- return "HSDPA";
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- return "HSUPA";
- case TelephonyManager.NETWORK_TYPE_HSPA:
- return "HSPA";
- case TelephonyManager.NETWORK_TYPE_CDMA:
- return "CDMA";
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- return "CDMA - EvDo rev. 0";
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- return "CDMA - EvDo rev. A";
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- return "CDMA - EvDo rev. B";
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- return "CDMA - 1xRTT";
- case TelephonyManager.NETWORK_TYPE_LTE:
- return "LTE";
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- return "CDMA - eHRPD";
- case TelephonyManager.NETWORK_TYPE_IDEN:
- return "iDEN";
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- return "HSPA+";
- case TelephonyManager.NETWORK_TYPE_GSM:
- return "GSM";
- case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
- return "TD_SCDMA";
- case TelephonyManager.NETWORK_TYPE_IWLAN:
- return "IWLAN";
-
- //TODO: This network type is marked as hidden because it is not a
- // true network type and we are looking to remove it completely from the available list
- // of network types. Since this method is only used for logging, in the event that this
- // network type is selected, the log will read as "Unknown."
- //case TelephonyManager.NETWORK_TYPE_LTE_CA:
- // return "LTE_CA";
-
- case TelephonyManager.NETWORK_TYPE_NR:
- return "NR";
- default:
- return "UNKNOWN";
- }
- }
-
/** Returns a new PreciseCallState object with default values. */
private static PreciseCallState createPreciseCallState() {
return new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 88492ed..35b5f1b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2010,7 +2010,7 @@
@Override
public void hasFeatures(IAccountManagerResponse response,
- Account account, String[] features, String opPackageName) {
+ Account account, String[] features, int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
mAppOpsManager.checkPackage(callingUid, opPackageName);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2018,12 +2018,22 @@
+ ", response " + response
+ ", features " + Arrays.toString(features)
+ ", caller's uid " + callingUid
+ + ", userId " + userId
+ ", pid " + Binder.getCallingPid());
}
Preconditions.checkArgument(account != null, "account cannot be null");
Preconditions.checkArgument(response != null, "response cannot be null");
Preconditions.checkArgument(features != null, "features cannot be null");
- int userId = UserHandle.getCallingUserId();
+
+ if (userId != UserHandle.getCallingUserId()
+ && callingUid != Process.SYSTEM_UID
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("User " + UserHandle.getCallingUserId()
+ + " trying to check account features for " + userId);
+ }
+
checkReadAccountsPermitted(callingUid, account.type, userId,
opPackageName);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9154231..6719fdb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -112,6 +112,7 @@
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.BackgroundStartPrivileges;
import android.app.ForegroundServiceDelegationOptions;
import android.app.ForegroundServiceStartNotAllowedException;
import android.app.ForegroundServiceTypePolicy;
@@ -733,13 +734,13 @@
@Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- callingPackage, callingFeatureId, userId, false, null);
+ callingPackage, callingFeatureId, userId, BackgroundStartPrivileges.NONE);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired,
String callingPackage, @Nullable String callingFeatureId, final int userId,
- boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
+ BackgroundStartPrivileges backgroundStartPrivileges)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -777,7 +778,7 @@
// the timeout)
ServiceRecord r = res.record;
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
- allowBackgroundActivityStarts, false /* isBindService */);
+ backgroundStartPrivileges, false /* isBindService */);
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
@@ -894,8 +895,8 @@
// The package could be frozen (meaning it's doing surgery), defer the actual
// start until the package is unfrozen.
if (deferServiceBringupIfFrozenLocked(r, service, callingPackage, callingFeatureId,
- callingUid, callingPid, fgRequired, callerFg, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken, false, null)) {
+ callingUid, callingPid, fgRequired, callerFg, userId,
+ backgroundStartPrivileges, false, null)) {
return null;
}
@@ -916,8 +917,8 @@
final ComponentName realResult =
startServiceInnerLocked(r, service, callingUid, callingPid,
getCallingProcessNameLocked(callingUid, callingPid, callingPackage),
- fgRequired, callerFg, allowBackgroundActivityStarts,
- backgroundActivityStartsToken);
+ fgRequired, callerFg,
+ backgroundStartPrivileges);
if (res.aliasComponent != null
&& !realResult.getPackageName().startsWith("!")
&& !realResult.getPackageName().startsWith("?")) {
@@ -937,8 +938,9 @@
private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
int callingUid, int callingPid, String callingProcessName, boolean fgRequired,
- boolean callerFg, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException {
+ boolean callerFg,
+ BackgroundStartPrivileges backgroundStartPrivileges)
+ throws TransactionTooLargeException {
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
service, callingUid, r.packageName, r.userId);
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
@@ -1031,8 +1033,8 @@
"Not potential delay (user " + r.userId + " not started): " + r);
}
}
- if (allowBackgroundActivityStarts) {
- r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
+ if (backgroundStartPrivileges.allowsAny()) {
+ r.allowBgActivityStartsOnServiceStart(backgroundStartPrivileges);
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting,
callingUid, callingProcessName, wasStartRequested);
@@ -1140,7 +1142,7 @@
private boolean deferServiceBringupIfFrozenLocked(ServiceRecord s, Intent serviceIntent,
String callingPackage, @Nullable String callingFeatureId,
int callingUid, int callingPid, boolean fgRequired, boolean callerFg, int userId,
- boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
+ BackgroundStartPrivileges backgroundStartPrivileges,
boolean isBinding, IServiceConnection connection) {
final PackageManagerInternal pm = mAm.getPackageManagerInternal();
final boolean frozen = pm.isPackageFrozen(s.packageName, callingUid, s.userId);
@@ -1188,7 +1190,7 @@
try {
startServiceInnerLocked(s, serviceIntent, callingUid, callingPid,
callingProcessName, fgRequired, callerFg,
- allowBackgroundActivityStarts, backgroundActivityStartsToken);
+ backgroundStartPrivileges);
} catch (TransactionTooLargeException e) {
/* ignore - local call */
}
@@ -2007,7 +2009,7 @@
resetFgsRestrictionLocked(r);
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
- false /* allowBackgroundActivityStarts */,
+ BackgroundStartPrivileges.NONE,
false /* isBindService */);
final String temp = "startForegroundDelayMs:" + delayMs;
if (r.mInfoAllowStartForeground != null) {
@@ -2027,7 +2029,7 @@
// started. Check for app state again.
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
- false /* allowBackgroundActivityStarts */,
+ BackgroundStartPrivileges.NONE,
false /* isBindService */);
}
// If the foreground service is not started from TOP process, do not allow it to
@@ -3301,7 +3303,8 @@
// The package could be frozen (meaning it's doing surgery), defer the actual
// binding until the package is unfrozen.
boolean packageFrozen = deferServiceBringupIfFrozenLocked(s, service, callingPackage, null,
- callingUid, callingPid, false, callerFg, userId, false, null, true, connection);
+ callingUid, callingPid, false, callerFg, userId, BackgroundStartPrivileges.NONE,
+ true, connection);
// If permissions need a review before any of the app components can run,
// we schedule binding to the service but do not start its process, then
@@ -3400,7 +3403,7 @@
}
}
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
- false /* allowBackgroundActivityStarts */, true /* isBindService */);
+ BackgroundStartPrivileges.NONE, true /* isBindService */);
if (s.app != null) {
ProcessServiceRecord servicePsr = s.app.mServices;
@@ -7056,7 +7059,7 @@
*/
private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
- boolean allowBackgroundActivityStarts, boolean isBindService) {
+ BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
// Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
@@ -7066,7 +7069,7 @@
if (!r.mAllowWhileInUsePermissionInFgs
|| (r.mAllowStartForeground == REASON_DENIED)) {
final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
- callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts,
+ callingPackage, callingPid, callingUid, r, backgroundStartPrivileges,
isBindService);
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
@@ -7074,7 +7077,7 @@
if (r.mAllowStartForeground == REASON_DENIED) {
r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked(
allowWhileInUse, callingPackage, callingPid, callingUid, intent, r,
- userId, isBindService);
+ backgroundStartPrivileges, isBindService);
}
}
}
@@ -7094,10 +7097,10 @@
}
final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
callingPackage, callingPid, callingUid, null /* serviceRecord */,
- false /* allowBackgroundActivityStarts */, false);
+ BackgroundStartPrivileges.NONE, false);
@ReasonCode int allowStartFgs = shouldAllowFgsStartForegroundNoBindingCheckLocked(
allowWhileInUse, callingPid, callingUid, callingPackage, null /* targetService */,
- false /* isBindService */);
+ BackgroundStartPrivileges.NONE);
if (allowStartFgs == REASON_DENIED) {
if (canBindingClientStartFgsLocked(callingUid) != null) {
@@ -7117,7 +7120,7 @@
*/
private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
int callingPid, int callingUid, @Nullable ServiceRecord targetService,
- boolean allowBackgroundActivityStarts, boolean isBindService) {
+ BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
int ret = REASON_DENIED;
final int uidState = mAm.getUidStateLocked(callingUid);
@@ -7138,7 +7141,7 @@
if (ret == REASON_DENIED) {
// Is the allow activity background start flag on?
- if (allowBackgroundActivityStarts) {
+ if (backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
ret = REASON_START_ACTIVITY_FLAG;
}
}
@@ -7271,12 +7274,13 @@
shouldAllowFgsWhileInUsePermissionLocked(
clientPackageName,
clientPid, clientUid, null /* serviceRecord */,
- false /* allowBackgroundActivityStarts */, false);
+ BackgroundStartPrivileges.NONE, false);
final @ReasonCode int allowStartFgs =
shouldAllowFgsStartForegroundNoBindingCheckLocked(
allowWhileInUse2,
clientPid, clientUid, clientPackageName,
- null /* targetService */, false);
+ null /* targetService */,
+ BackgroundStartPrivileges.NONE);
if (allowStartFgs != REASON_DENIED) {
return new Pair<>(allowStartFgs, clientPackageName);
} else {
@@ -7308,11 +7312,12 @@
*/
private @ReasonCode int shouldAllowFgsStartForegroundWithBindingCheckLocked(
@ReasonCode int allowWhileInUse, String callingPackage, int callingPid,
- int callingUid, Intent intent, ServiceRecord r, int userId, boolean isBindService) {
+ int callingUid, Intent intent, ServiceRecord r,
+ BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
ActivityManagerService.FgsTempAllowListItem tempAllowListReason =
r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
int ret = shouldAllowFgsStartForegroundNoBindingCheckLocked(allowWhileInUse, callingPid,
- callingUid, callingPackage, r, isBindService);
+ callingUid, callingPackage, r, backgroundStartPrivileges);
String bindFromPackage = null;
if (ret == REASON_DENIED) {
@@ -7358,7 +7363,8 @@
private @ReasonCode int shouldAllowFgsStartForegroundNoBindingCheckLocked(
@ReasonCode int allowWhileInUse, int callingPid, int callingUid, String callingPackage,
- @Nullable ServiceRecord targetService, boolean isBindService) {
+ @Nullable ServiceRecord targetService,
+ BackgroundStartPrivileges backgroundStartPrivileges) {
int ret = allowWhileInUse;
if (ret == REASON_DENIED) {
@@ -7406,6 +7412,12 @@
}
if (ret == REASON_DENIED) {
+ if (backgroundStartPrivileges.allowsBackgroundFgsStarts()) {
+ ret = REASON_START_ACTIVITY_FLAG;
+ }
+ }
+
+ if (ret == REASON_DENIED) {
if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
callingPackage)) {
ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
@@ -7489,6 +7501,7 @@
ret = REASON_OPT_OUT_REQUESTED;
}
}
+
return ret;
}
@@ -7652,7 +7665,7 @@
String callingPackage) {
return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
/* targetService */ null,
- /* allowBackgroundActivityStarts */ false, false)
+ BackgroundStartPrivileges.NONE, false)
!= REASON_DENIED;
}
@@ -7759,7 +7772,7 @@
r.mFgsEnterTime = SystemClock.uptimeMillis();
r.foregroundServiceType = options.mForegroundServiceTypes;
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
- false, false);
+ BackgroundStartPrivileges.NONE, false);
final ProcessServiceRecord psr = callerApp.mServices;
final boolean newService = psr.startService(r);
// updateOomAdj.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 09c4eb2..e962fb0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -183,6 +183,7 @@
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.app.ApplicationThreadConstants;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.ComponentOptions;
import android.app.ContentProviderHolder;
@@ -3990,8 +3991,8 @@
null /* resultData */, null /* resultExtras */,
isInstantApp ? permission.ACCESS_INSTANT_APPS : null,
null /* bOptions */, false /* serialized */, false /* sticky */,
- resolvedUserId, false /* allowBackgroundActivityStarts */,
- null /* backgroundActivityStartsToken */, visibilityAllowList);
+ resolvedUserId, BackgroundStartPrivileges.NONE,
+ visibilityAllowList);
}
if (observer != null) {
@@ -4538,8 +4539,7 @@
null /* requiredPermissions */, null /* excludedPermissions */,
null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), userId, false /* allowBackgroundActivityStarts */,
- null /* backgroundActivityStartsToken */,
+ Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE,
broadcastAllowList, null /* filterExtrasForReceiver */);
}
@@ -6694,6 +6694,10 @@
@Override
public void appNotResponding(final String reason) {
+ appNotResponding(reason, /*isContinuousAnr*/ false);
+ }
+
+ public void appNotResponding(final String reason, boolean isContinuousAnr) {
TimeoutRecord timeoutRecord = TimeoutRecord.forApp("App requested: " + reason);
final int callingPid = Binder.getCallingPid();
@@ -6706,7 +6710,7 @@
}
mAnrHelper.appNotResponding(app, null, app.info, null, null, false,
- timeoutRecord);
+ timeoutRecord, isContinuousAnr);
}
}
@@ -13774,8 +13778,9 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
- receivers, null, null, 0, null, null, false, true, true, -1, false,
- null, false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
+ receivers, null, null, 0, null, null, false, true, true, -1,
+ BackgroundStartPrivileges.NONE,
+ false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
null /* filterExtrasForReceiver */);
queue.enqueueBroadcastLocked(r);
}
@@ -14052,8 +14057,7 @@
resolvedType, null, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
- false /* allowBackgroundActivityStarts */,
- null /* tokenNeededForBackgroundActivityStarts */,
+ BackgroundStartPrivileges.NONE,
null /* broadcastAllowList */, null /* filterExtrasForReceiver */);
}
@@ -14065,8 +14069,7 @@
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
- boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken,
+ BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
@@ -14074,7 +14077,7 @@
intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken, broadcastAllowList,
+ backgroundStartPrivileges, broadcastAllowList,
filterExtrasForReceiver);
BroadcastQueue.traceEnd(cookie);
return res;
@@ -14088,8 +14091,7 @@
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
- boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken,
+ BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
// Ensure all internal loopers are registered for idle checks
@@ -14210,9 +14212,8 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else {
- allowBackgroundActivityStarts = true;
// We set the token to null since if it wasn't for it we'd allow anyway here
- backgroundActivityStartsToken = null;
+ backgroundStartPrivileges = BackgroundStartPrivileges.ALLOW_BAL;
}
}
@@ -14731,8 +14732,8 @@
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
registeredReceivers, resultToApp, resultTo, resultCode, resultData,
- resultExtras, ordered, sticky, false, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
+ resultExtras, ordered, sticky, false, userId,
+ backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
queue.enqueueBroadcastLocked(r);
registeredReceivers = null;
@@ -14825,8 +14826,8 @@
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
- ordered, sticky, false, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
+ ordered, sticky, false, userId,
+ backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
queue.enqueueBroadcastLocked(r);
@@ -14971,7 +14972,7 @@
intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid,
- callingPid, userId, false, null, null, null);
+ callingPid, userId, BackgroundStartPrivileges.NONE, null, null);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -14983,8 +14984,9 @@
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode,
String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
- boolean serialized, boolean sticky, int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList) {
+ boolean serialized, boolean sticky, int userId,
+ BackgroundStartPrivileges backgroundStartPrivileges,
+ @Nullable int[] broadcastAllowList) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -14995,8 +14997,8 @@
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
resultToApp, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1,
- uid, realCallingUid, realCallingPid, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken, broadcastAllowList,
+ uid, realCallingUid, realCallingPid, userId,
+ backgroundStartPrivileges, broadcastAllowList,
null /* filterExtrasForReceiver */);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -17366,6 +17368,11 @@
}
@Override
+ public Pair<Integer, Integer> getCurrentAndTargetUserIds() {
+ return mUserController.getCurrentAndTargetUserIds();
+ }
+
+ @Override
public int getCurrentUserId() {
return mUserController.getCurrentUserId();
}
@@ -17583,16 +17590,16 @@
IApplicationThread resultToThread, IIntentReceiver resultTo, int resultCode,
String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
boolean serialized, boolean sticky, int userId,
- boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken,
+ BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList) {
synchronized (ActivityManagerService.this) {
final ProcessRecord resultToApp = getRecordForAppLOSP(resultToThread);
return ActivityManagerService.this.broadcastIntentInPackage(packageName, featureId,
uid, realCallingUid, realCallingPid, intent, resolvedType, resultToApp,
resultTo, resultCode, resultData, resultExtras, requiredPermission,
- bOptions, serialized, sticky, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken, broadcastAllowList);
+ bOptions, serialized, sticky, userId,
+ backgroundStartPrivileges,
+ broadcastAllowList);
}
}
@@ -17618,8 +17625,7 @@
null /*excludedPermissions*/, null /*excludedPackages*/,
AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
- userId, false /*allowBackgroundStarts*/,
- null /*tokenNeededForBackgroundActivityStarts*/,
+ userId, BackgroundStartPrivileges.NONE,
appIdAllowList, filterExtrasForReceiver);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -17646,8 +17652,7 @@
@Override
public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
boolean fgRequired, String callingPackage, @Nullable String callingFeatureId,
- int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken)
+ int userId, BackgroundStartPrivileges backgroundStartPrivileges)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) {
Slog.v(TAG_SERVICE,
@@ -17664,8 +17669,8 @@
synchronized (ActivityManagerService.this) {
res = mServices.startServiceLocked(null, service,
resolvedType, -1, uid, fgRequired, callingPackage,
- callingFeatureId, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken);
+ callingFeatureId, userId,
+ backgroundStartPrivileges);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -18400,7 +18405,8 @@
}
}
mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
- parentShortComponentName, parentProcess, aboveSystem, timeoutRecord);
+ parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
+ /*isContinuousAnr*/ true);
}
return true;
diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index 71c80ea..463a2f8 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -96,13 +96,13 @@
void appNotResponding(ProcessRecord anrProcess, TimeoutRecord timeoutRecord) {
appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
null /* parentShortComponentName */, null /* parentProcess */,
- false /* aboveSystem */, timeoutRecord);
+ false /* aboveSystem */, timeoutRecord, /*isContinuousAnr*/ false);
}
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem,
- TimeoutRecord timeoutRecord) {
+ TimeoutRecord timeoutRecord, boolean isContinuousAnr) {
try {
timeoutRecord.mLatencyTracker.appNotRespondingStarted();
final int incomingPid = anrProcess.mPid;
@@ -132,7 +132,7 @@
timeoutRecord.mLatencyTracker.anrRecordPlacingOnQueueWithSize(mAnrRecords.size());
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem,
- mAuxiliaryTaskExecutor, timeoutRecord));
+ mAuxiliaryTaskExecutor, timeoutRecord, isContinuousAnr));
}
startAnrConsumerIfNeeded();
} finally {
@@ -230,10 +230,12 @@
final boolean mAboveSystem;
final ExecutorService mAuxiliaryTaskExecutor;
final long mTimestamp = SystemClock.uptimeMillis();
+ final boolean mIsContinuousAnr;
AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem,
- ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord) {
+ ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord,
+ boolean isContinuousAnr) {
mApp = anrProcess;
mPid = anrProcess.mPid;
mActivityShortComponentName = activityShortComponentName;
@@ -243,6 +245,7 @@
mParentProcess = parentProcess;
mAboveSystem = aboveSystem;
mAuxiliaryTaskExecutor = auxiliaryTaskExecutor;
+ mIsContinuousAnr = isContinuousAnr;
}
void appNotResponding(boolean onlyDumpSelf) {
@@ -250,7 +253,8 @@
mTimeoutRecord.mLatencyTracker.anrProcessingStarted();
mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
mParentShortComponentName, mParentProcess, mAboveSystem,
- mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf);
+ mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf,
+ mIsContinuousAnr);
} finally {
mTimeoutRecord.mLatencyTracker.anrProcessingEnded();
}
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 5fe8427..d3e91da 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -169,8 +169,10 @@
errState.getDialogController().clearAnrDialogs();
}
mService.mServices.scheduleServiceTimeoutLocked(app);
- // If the app remains unresponsive, show the dialog again after a delay.
- mService.mInternal.rescheduleAnrDialog(mData);
+ if (mData.isContinuousAnr) {
+ // If the app remains unresponsive, show the dialog again after a delay.
+ mService.mInternal.rescheduleAnrDialog(mData);
+ }
}
break;
}
@@ -197,10 +199,17 @@
final ApplicationInfo aInfo;
final boolean aboveSystem;
- Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem) {
+ // If true, then even if the user presses "WAIT" on the ANR dialog,
+ // we'll show it again until the app start responding again.
+ // (we only use it for input dispatch ANRs)
+ final boolean isContinuousAnr;
+
+ Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem,
+ boolean isContinuousAnr) {
this.proc = proc;
this.aInfo = aInfo;
this.aboveSystem = aboveSystem;
+ this.isContinuousAnr = isContinuousAnr;
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index a86efa3..b1a01cc 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -561,7 +561,7 @@
// ...then schedule the removal of the token after the extended timeout
mHandler.postAtTime(() -> {
synchronized (mService) {
- app.removeAllowBackgroundActivityStartsToken(r);
+ app.removeBackgroundStartPrivileges(r);
}
}, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
}
@@ -603,11 +603,11 @@
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG_BROADCAST, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
- if (r.allowBackgroundActivityStarts && r.curApp != null) {
+ if (r.mBackgroundStartPrivileges.allowsAny() && r.curApp != null) {
if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) {
// if the receiver has run for more than allowed bg activity start timeout,
// just remove the token for this process now and we're done
- r.curApp.removeAllowBackgroundActivityStartsToken(r);
+ r.curApp.removeBackgroundStartPrivileges(r);
} else {
// It gets more time; post the removal to happen at the appropriate moment
postActivityStartTokenRemoval(r.curApp, r);
@@ -840,7 +840,7 @@
} else {
r.receiverTime = SystemClock.uptimeMillis();
r.scheduledTime[index] = r.receiverTime;
- maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
+ maybeAddBackgroundStartPrivileges(filter.receiverList.app, r);
maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
@@ -852,7 +852,8 @@
// parallel broadcasts are fire-and-forget, not bookended by a call to
// finishReceiverLocked(), so we manage their activity-start token here
if (filter.receiverList.app != null
- && r.allowBackgroundActivityStarts && !r.ordered) {
+ && r.mBackgroundStartPrivileges.allowsAny()
+ && !r.ordered) {
postActivityStartTokenRemoval(filter.receiverList.app, r);
}
}
@@ -863,7 +864,7 @@
Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
// Clean up ProcessRecord state related to this broadcast attempt
if (filter.receiverList.app != null) {
- filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
+ filter.receiverList.app.removeBackgroundStartPrivileges(r);
if (ordered) {
filter.receiverList.app.mReceivers.removeCurReceiver(r);
// Something wrong, its oom adj could be downgraded, but not in a hurry.
@@ -1303,7 +1304,7 @@
scheduleBroadcastsLocked();
} else {
if (filter.receiverList != null) {
- maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
+ maybeAddBackgroundStartPrivileges(filter.receiverList.app, r);
// r is guaranteed ordered at this point, so we know finishReceiverLocked()
// will get a callback and handle the activity start token lifecycle.
}
@@ -1393,7 +1394,7 @@
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
- maybeAddAllowBackgroundActivityStartsToken(app, r);
+ maybeAddBackgroundStartPrivileges(app, r);
r.mIsReceiverAppRunning = true;
processCurBroadcastLocked(r, app);
return;
@@ -1450,7 +1451,7 @@
return;
}
- maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
+ maybeAddBackgroundStartPrivileges(r.curApp, r);
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
@@ -1537,8 +1538,8 @@
mService.getUidStateLocked(targetUid));
}
- private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) {
- if (r == null || proc == null || !r.allowBackgroundActivityStarts) {
+ private void maybeAddBackgroundStartPrivileges(ProcessRecord proc, BroadcastRecord r) {
+ if (r == null || proc == null || !r.mBackgroundStartPrivileges.allowsAny()) {
return;
}
String msgToken = (proc.toShortString() + r.toString()).intern();
@@ -1546,7 +1547,7 @@
// that request - we don't want the token to be swept from under our feet...
mHandler.removeCallbacksAndMessages(msgToken);
// ...then add the token
- proc.addOrUpdateAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken);
+ proc.addOrUpdateBackgroundStartPrivileges(r, r.mBackgroundStartPrivileges);
}
final void setBroadcastTimeoutLocked(long timeoutTime) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 8fc4a21..99e2ac7 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -281,7 +281,7 @@
final ProcessRecord app = (ProcessRecord) args.arg1;
final BroadcastRecord r = (BroadcastRecord) args.arg2;
args.recycle();
- app.removeAllowBackgroundActivityStartsToken(r);
+ app.removeBackgroundStartPrivileges(r);
}
return true;
}
@@ -1020,8 +1020,8 @@
MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis);
}
- if (r.allowBackgroundActivityStarts) {
- app.addOrUpdateAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken);
+ if (r.mBackgroundStartPrivileges.allowsAny()) {
+ app.addOrUpdateBackgroundStartPrivileges(r, r.mBackgroundStartPrivileges);
final long timeout = r.isForeground() ? mFgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT
: mBgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT;
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9679fb8..4304377 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -32,6 +32,7 @@
import android.annotation.UptimeMillisLong;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.compat.CompatChanges;
import android.content.ComponentName;
@@ -42,7 +43,6 @@
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.PrintWriterPrinter;
@@ -135,12 +135,8 @@
int deferredCount; // number of receivers in deferred state.
@Nullable BroadcastQueue queue; // the outbound queue handling this broadcast
- // if set to true, app's process will be temporarily allowed to start activities from background
- // for the duration of the broadcast dispatch
- final boolean allowBackgroundActivityStarts;
- // token used to trace back the grant for activity starts, optional
- @Nullable
- final IBinder mBackgroundActivityStartsToken;
+ // Determines the privileges the app's process has in regard to background starts.
+ final BackgroundStartPrivileges mBackgroundStartPrivileges;
// Filter the intent extras by using the rules of the package visibility before broadcasting
// the intent to the receiver.
@@ -371,8 +367,9 @@
BroadcastOptions _options, List _receivers,
ProcessRecord _resultToApp, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
- boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt,
+ boolean _initialSticky, int _userId,
+ @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
+ boolean timeoutExempt,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
@@ -414,8 +411,7 @@
userId = _userId;
nextReceiver = 0;
state = IDLE;
- this.allowBackgroundActivityStarts = allowBackgroundActivityStarts;
- mBackgroundActivityStartsToken = backgroundActivityStartsToken;
+ mBackgroundStartPrivileges = backgroundStartPrivileges;
this.timeoutExempt = timeoutExempt;
alarm = options != null && options.isAlarmBroadcast();
pushMessage = options != null && options.isPushMessagingBroadcast();
@@ -479,8 +475,7 @@
manifestCount = from.manifestCount;
manifestSkipCount = from.manifestSkipCount;
queue = from.queue;
- allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
- mBackgroundActivityStartsToken = from.mBackgroundActivityStartsToken;
+ mBackgroundStartPrivileges = from.mBackgroundStartPrivileges;
timeoutExempt = from.timeoutExempt;
alarm = from.alarm;
pushMessage = from.pushMessage;
@@ -521,8 +516,8 @@
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
splitReceivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
- ordered, sticky, initialSticky, userId, allowBackgroundActivityStarts,
- mBackgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
+ ordered, sticky, initialSticky, userId,
+ mBackgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
split.enqueueTime = this.enqueueTime;
split.enqueueRealTime = this.enqueueRealTime;
split.enqueueClockTime = this.enqueueClockTime;
@@ -601,7 +596,7 @@
requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
uid2receiverList.valueAt(i), null /* _resultToApp */, null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt,
+ mBackgroundStartPrivileges, timeoutExempt,
filterExtrasForReceiver);
br.enqueueTime = this.enqueueTime;
br.enqueueRealTime = this.enqueueRealTime;
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 17fff91..f9c0c49 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -77,6 +77,7 @@
Context.BIND_NOT_VISIBLE,
Context.BIND_NOT_PERCEPTIBLE,
Context.BIND_INCLUDE_CAPABILITIES,
+ Context.BIND_ALLOW_ACTIVITY_STARTS,
};
private static final int[] BIND_PROTO_ENUMS = new int[] {
ConnectionRecordProto.AUTO_CREATE,
@@ -96,6 +97,7 @@
ConnectionRecordProto.NOT_VISIBLE,
ConnectionRecordProto.NOT_PERCEPTIBLE,
ConnectionRecordProto.INCLUDE_CAPABILITIES,
+ ConnectionRecordProto.ALLOW_ACTIVITY_STARTS,
};
void dump(PrintWriter pw, String prefix) {
@@ -237,6 +239,9 @@
if ((flags & Context.BIND_NOT_PERCEPTIBLE) != 0) {
sb.append("!PRCP ");
}
+ if ((flags & Context.BIND_ALLOW_ACTIVITY_STARTS) != 0) {
+ sb.append("BALF ");
+ }
if ((flags & Context.BIND_INCLUDE_CAPABILITIES) != 0) {
sb.append("CAPS ");
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index dbd58eb..81655cf 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2620,7 +2620,7 @@
}
state.setCurRawAdj(adj);
-
+ adj = psr.modifyRawOomAdj(adj);
if (adj > state.getMaxAdj()) {
adj = state.getMaxAdj();
if (adj <= PERCEPTIBLE_LOW_APP_ADJ) {
@@ -2650,7 +2650,7 @@
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
- state.setCurAdj(psr.modifyRawOomAdj(adj));
+ state.setCurAdj(adj);
state.setCurCapability(capability);
state.setCurrentSchedulingGroup(schedGroup);
state.setCurProcState(procState);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index fed0b11..874fda3 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -330,20 +331,42 @@
return activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission();
}
- public static boolean isPendingIntentBalAllowedByCaller(
- @Nullable ActivityOptions activityOptions) {
+ /**
+ * Return the {@link BackgroundStartPrivileges} the activity options grant the PendingIntent to
+ * use caller's BAL permission.
+ */
+ public static BackgroundStartPrivileges getBackgroundStartPrivilegesAllowedByCaller(
+ @Nullable ActivityOptions activityOptions, int callingUid) {
if (activityOptions == null) {
- return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+ // since the ActivityOptions were not created by the app itself, determine the default
+ // for the app
+ return getDefaultBackgroundStartPrivileges(callingUid);
}
- return isPendingIntentBalAllowedByCaller(activityOptions.toBundle());
+ return getBackgroundStartPrivilegesAllowedByCaller(activityOptions.toBundle(),
+ callingUid);
}
- private static boolean isPendingIntentBalAllowedByCaller(@Nullable Bundle options) {
- if (options == null) {
- return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+ private static BackgroundStartPrivileges getBackgroundStartPrivilegesAllowedByCaller(
+ @Nullable Bundle options, int callingUid) {
+ if (options == null || !options.containsKey(
+ ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED)) {
+ return getDefaultBackgroundStartPrivileges(callingUid);
}
- return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
- ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT);
+ return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED)
+ ? BackgroundStartPrivileges.ALLOW_BAL
+ : BackgroundStartPrivileges.NONE;
+ }
+
+ /**
+ * Default {@link BackgroundStartPrivileges} to be used if the intent sender has not made an
+ * explicit choice.
+ *
+ * @hide
+ */
+ public static BackgroundStartPrivileges getDefaultBackgroundStartPrivileges(int callingUid) {
+ // TODO: In the next step this will return ALLOW_FGS instead, if the app that sent the
+ // PendingIntent is targeting Android U
+ return BackgroundStartPrivileges.ALLOW_BAL;
}
@Deprecated
@@ -493,11 +516,6 @@
if (userId == UserHandle.USER_CURRENT) {
userId = controller.mUserController.getCurrentOrTargetUserId();
}
- // temporarily allow receivers and services to open activities from background if the
- // PendingIntent.send() caller was foreground at the time of sendInner() call
- final boolean allowTrampoline = uid != callingUid
- && controller.mAtmInternal.isUidForeground(callingUid)
- && isPendingIntentBalAllowedByCaller(options);
// note: we on purpose don't pass in the information about the PendingIntent's creator,
// like pid or ProcessRecord, to the ActivityTaskManagerInternal calls below, because
@@ -515,8 +533,7 @@
allIntents, allResolvedTypes, resultTo, mergedOptions, userId,
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
- mAllowBgActivityStartsForActivitySender.contains(
- allowlistToken));
+ getBackgroundStartPrivilegesForActivitySender(allowlistToken));
} else {
res = controller.mAtmInternal.startActivityInPackage(uid, callingPid,
callingUid, key.packageName, key.featureId, finalIntent,
@@ -524,8 +541,7 @@
mergedOptions, userId, null, "PendingIntentRecord",
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
- mAllowBgActivityStartsForActivitySender.contains(
- allowlistToken));
+ getBackgroundStartPrivilegesForActivitySender(allowlistToken));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -537,17 +553,17 @@
break;
case ActivityManager.INTENT_SENDER_BROADCAST:
try {
- final boolean allowedByToken =
- mAllowBgActivityStartsForBroadcastSender.contains(allowlistToken);
- final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
-
+ final BackgroundStartPrivileges backgroundStartPrivileges =
+ getBackgroundStartPrivilegesForActivitySender(
+ mAllowBgActivityStartsForBroadcastSender, allowlistToken,
+ options, callingUid);
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
key.featureId, uid, callingUid, callingPid, finalIntent,
resolvedType, finishedReceiverThread, finishedReceiver, code, null,
null, requiredPermission, options, (finishedReceiver != null),
- false, userId, allowedByToken || allowTrampoline, bgStartsToken,
+ false, userId, backgroundStartPrivileges,
null /* broadcastAllowList */);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
@@ -559,14 +575,14 @@
case ActivityManager.INTENT_SENDER_SERVICE:
case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
try {
- final boolean allowedByToken =
- mAllowBgActivityStartsForServiceSender.contains(allowlistToken);
- final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
-
+ final BackgroundStartPrivileges backgroundStartPrivileges =
+ getBackgroundStartPrivilegesForActivitySender(
+ mAllowBgActivityStartsForServiceSender, allowlistToken,
+ options, callingUid);
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
key.packageName, key.featureId, userId,
- allowedByToken || allowTrampoline, bgStartsToken);
+ backgroundStartPrivileges);
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
} catch (TransactionTooLargeException e) {
@@ -589,6 +605,27 @@
return res;
}
+ private BackgroundStartPrivileges getBackgroundStartPrivilegesForActivitySender(
+ IBinder allowlistToken) {
+ return mAllowBgActivityStartsForActivitySender.contains(allowlistToken)
+ ? BackgroundStartPrivileges.allowBackgroundActivityStarts(allowlistToken)
+ : BackgroundStartPrivileges.NONE;
+ }
+
+ private BackgroundStartPrivileges getBackgroundStartPrivilegesForActivitySender(
+ ArraySet<IBinder> allowedTokenSet, IBinder allowlistToken,
+ Bundle options, int callingUid) {
+ if (allowedTokenSet.contains(allowlistToken)) {
+ return BackgroundStartPrivileges.allowBackgroundActivityStarts(allowlistToken);
+ }
+ // temporarily allow receivers and services to open activities from background if the
+ // PendingIntent.send() caller was foreground at the time of sendInner() call
+ if (uid != callingUid && controller.mAtmInternal.isUidForeground(callingUid)) {
+ return getBackgroundStartPrivilegesAllowedByCaller(options, callingUid);
+ }
+ return BackgroundStartPrivileges.NONE;
+ }
+
@Override
protected void finalize() throws Throwable {
try {
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 68d906b..9bb63d3 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -263,7 +263,8 @@
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, TimeoutRecord timeoutRecord,
- ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf) {
+ ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf,
+ boolean isContinuousAnr) {
String annotation = timeoutRecord.mReason;
AnrLatencyTracker latencyTracker = timeoutRecord.mLatencyTracker;
Future<?> updateCpuStatsNowFirstCall = null;
@@ -630,7 +631,8 @@
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
- msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);
+ msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem,
+ isContinuousAnr);
mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index cf91429..e6cb596 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -25,6 +25,7 @@
import android.app.ApplicationExitInfo;
import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
@@ -1290,16 +1291,16 @@
* {@param originatingToken} if you have one such originating token, this is useful for tracing
* back the grant in the case of the notification token.
*/
- void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
- @Nullable IBinder originatingToken) {
+ void addOrUpdateBackgroundStartPrivileges(Binder entity,
+ BackgroundStartPrivileges backgroundStartPrivileges) {
Objects.requireNonNull(entity);
- mWindowProcessController.addOrUpdateAllowBackgroundActivityStartsToken(entity,
- originatingToken);
+ mWindowProcessController.addOrUpdateBackgroundStartPrivileges(entity,
+ backgroundStartPrivileges);
}
- void removeAllowBackgroundActivityStartsToken(Binder entity) {
+ void removeBackgroundStartPrivileges(Binder entity) {
Objects.requireNonNull(entity);
- mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity);
+ mWindowProcessController.removeBackgroundStartPrivileges(entity);
}
@Override
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index df442e8..bd7f96a 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -28,6 +28,7 @@
import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.wm.WindowProcessController;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -506,19 +507,21 @@
return mConnections.size();
}
- void addBoundClientUid(int clientUid) {
+ void addBoundClientUid(int clientUid, String clientPackageName, int bindFlags) {
mBoundClientUids.add(clientUid);
- mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids);
+ mApp.getWindowProcessController()
+ .addBoundClientUid(clientUid, clientPackageName, bindFlags);
}
void updateBoundClientUids() {
+ clearBoundClientUids();
if (mServices.isEmpty()) {
- clearBoundClientUids();
return;
}
// grab a set of clientUids of all mConnections of all services
final ArraySet<Integer> boundClientUids = new ArraySet<>();
final int serviceCount = mServices.size();
+ WindowProcessController controller = mApp.getWindowProcessController();
for (int j = 0; j < serviceCount; j++) {
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
mServices.valueAt(j).getConnections();
@@ -526,12 +529,13 @@
for (int conni = 0; conni < size; conni++) {
ArrayList<ConnectionRecord> c = conns.valueAt(conni);
for (int i = 0; i < c.size(); i++) {
- boundClientUids.add(c.get(i).clientUid);
+ ConnectionRecord cr = c.get(i);
+ boundClientUids.add(cr.clientUid);
+ controller.addBoundClientUid(cr.clientUid, cr.clientPackageName, cr.flags);
}
}
}
mBoundClientUids = boundClientUids;
- mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids);
}
void addBoundClientUidsOfNewService(ServiceRecord sr) {
@@ -542,15 +546,18 @@
for (int conni = conns.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> c = conns.valueAt(conni);
for (int i = 0; i < c.size(); i++) {
- mBoundClientUids.add(c.get(i).clientUid);
+ ConnectionRecord cr = c.get(i);
+ mBoundClientUids.add(cr.clientUid);
+ mApp.getWindowProcessController()
+ .addBoundClientUid(cr.clientUid, cr.clientPackageName, cr.flags);
+
}
}
- mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids);
}
void clearBoundClientUids() {
mBoundClientUids.clear();
- mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids);
+ mApp.getWindowProcessController().clearBoundClientUids();
}
@GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index def51b0..2a7f181 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -21,6 +21,7 @@
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.Process.INVALID_UID;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -28,6 +29,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.Notification;
import android.app.PendingIntent;
@@ -154,18 +156,20 @@
// any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
private boolean mIsAllowedBgActivityStartsByBinding;
- // is this service currently allowed to start activities from background by providing
- // allowBackgroundActivityStarts=true to startServiceLocked()?
- private boolean mIsAllowedBgActivityStartsByStart;
// used to clean up the state of mIsAllowedBgActivityStartsByStart after a timeout
private Runnable mCleanUpAllowBgActivityStartsByStartCallback;
private ProcessRecord mAppForAllowingBgActivityStartsByStart;
- // These are the originating tokens that currently allow bg activity starts by service start.
- // This is used to trace back the grant when starting activities. We only pass such token to the
- // ProcessRecord if it's the *only* cause for bg activity starts exemption, otherwise we pass
- // null.
+ // These are the privileges that currently allow bg activity starts by service start.
+ // Each time the contents of this list change #mBackgroundStartPrivilegesByStartMerged has to
+ // be updated to reflect the merged state. The merged state retains the attribution to the
+ // originating token only if it is the only cause for being privileged.
@GuardedBy("ams")
- private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
+ private ArrayList<BackgroundStartPrivileges> mBackgroundStartPrivilegesByStart =
+ new ArrayList<>();
+
+ // merged privileges for mBackgroundStartPrivilegesByStart (for performance)
+ private BackgroundStartPrivileges mBackgroundStartPrivilegesByStartMerged =
+ BackgroundStartPrivileges.NONE;
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
@@ -584,9 +588,9 @@
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByBinding=");
pw.println(mIsAllowedBgActivityStartsByBinding);
}
- if (mIsAllowedBgActivityStartsByStart) {
+ if (mBackgroundStartPrivilegesByStartMerged.allowsAny()) {
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
- pw.println(mIsAllowedBgActivityStartsByStart);
+ pw.println(mBackgroundStartPrivilegesByStartMerged);
}
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
@@ -822,27 +826,28 @@
if (mAppForAllowingBgActivityStartsByStart != null) {
if (mAppForAllowingBgActivityStartsByStart != proc) {
mAppForAllowingBgActivityStartsByStart
- .removeAllowBackgroundActivityStartsToken(this);
+ .removeBackgroundStartPrivileges(this);
ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback);
}
}
// Make sure the cleanup callback knows about the new process.
- mAppForAllowingBgActivityStartsByStart = mIsAllowedBgActivityStartsByStart
+ mAppForAllowingBgActivityStartsByStart =
+ mBackgroundStartPrivilegesByStartMerged.allowsAny()
? proc : null;
- if (mIsAllowedBgActivityStartsByStart
+ if (mBackgroundStartPrivilegesByStartMerged.allowsAny()
|| mIsAllowedBgActivityStartsByBinding) {
- proc.addOrUpdateAllowBackgroundActivityStartsToken(this,
- getExclusiveOriginatingToken());
+ proc.addOrUpdateBackgroundStartPrivileges(this,
+ getBackgroundStartPrivilegesWithExclusiveToken());
} else {
- proc.removeAllowBackgroundActivityStartsToken(this);
+ proc.removeBackgroundStartPrivileges(this);
}
}
if (app != null && app != proc) {
// If the old app is allowed to start bg activities because of a service start, leave it
// that way until the cleanup callback runs. Otherwise we can remove its bg activity
// start ability immediately (it can't be bound now).
- if (!mIsAllowedBgActivityStartsByStart) {
- app.removeAllowBackgroundActivityStartsToken(this);
+ if (mBackgroundStartPrivilegesByStartMerged.allowsNothing()) {
+ app.removeBackgroundStartPrivileges(this);
}
app.mServices.updateBoundClientUids();
app.mServices.updateHostingComonentTypeForBindingsLocked();
@@ -889,7 +894,7 @@
// if we have a process attached, add bound client uid of this connection to it
if (app != null) {
- app.mServices.addBoundClientUid(c.clientUid);
+ app.mServices.addBoundClientUid(c.clientUid, c.clientPackageName, c.flags);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BOUND_SERVICE);
}
}
@@ -942,9 +947,11 @@
* timeout. Note that the ability for starting background activities persists for the process
* even if the service is subsequently stopped.
*/
- void allowBgActivityStartsOnServiceStart(@Nullable IBinder originatingToken) {
- mBgActivityStartsByStartOriginatingTokens.add(originatingToken);
- setAllowedBgActivityStartsByStart(true);
+ void allowBgActivityStartsOnServiceStart(BackgroundStartPrivileges backgroundStartPrivileges) {
+ checkArgument(backgroundStartPrivileges.allowsAny());
+ mBackgroundStartPrivilegesByStart.add(backgroundStartPrivileges);
+ setAllowedBgActivityStartsByStart(
+ backgroundStartPrivileges.merge(mBackgroundStartPrivilegesByStartMerged));
if (app != null) {
mAppForAllowingBgActivityStartsByStart = app;
}
@@ -953,26 +960,31 @@
if (mCleanUpAllowBgActivityStartsByStartCallback == null) {
mCleanUpAllowBgActivityStartsByStartCallback = () -> {
synchronized (ams) {
- mBgActivityStartsByStartOriginatingTokens.remove(0);
- if (!mBgActivityStartsByStartOriginatingTokens.isEmpty()) {
+ mBackgroundStartPrivilegesByStart.remove(0);
+ if (!mBackgroundStartPrivilegesByStart.isEmpty()) {
+ // recalculate the merged token
+ mBackgroundStartPrivilegesByStartMerged =
+ BackgroundStartPrivileges.merge(mBackgroundStartPrivilegesByStart);
+
// There are other callbacks in the queue, let's just update the originating
// token
- if (mIsAllowedBgActivityStartsByStart) {
+ if (mBackgroundStartPrivilegesByStartMerged.allowsAny()) {
// mAppForAllowingBgActivityStartsByStart can be null here for example
// if get 2 calls to allowBgActivityStartsOnServiceStart() without a
// process attached to this ServiceRecord, so we need to perform a null
// check here.
if (mAppForAllowingBgActivityStartsByStart != null) {
mAppForAllowingBgActivityStartsByStart
- .addOrUpdateAllowBackgroundActivityStartsToken(
- this, getExclusiveOriginatingToken());
+ .addOrUpdateBackgroundStartPrivileges(this,
+ getBackgroundStartPrivilegesWithExclusiveToken());
}
} else {
Slog.wtf(TAG,
"Service callback to revoke bg activity starts by service "
+ "start triggered but "
- + "mIsAllowedBgActivityStartsByStart = false. This "
- + "should never happen.");
+ + "mBackgroundStartPrivilegesByStartMerged = "
+ + mBackgroundStartPrivilegesByStartMerged
+ + ". This should never happen.");
}
} else {
// Last callback on the queue
@@ -980,12 +992,12 @@
// The process we allowed is still running the service. We remove
// the ability by start, but it may still be allowed via bound
// connections.
- setAllowedBgActivityStartsByStart(false);
+ setAllowedBgActivityStartsByStart(BackgroundStartPrivileges.NONE);
} else if (mAppForAllowingBgActivityStartsByStart != null) {
// The process we allowed is not running the service. It therefore can't
// be bound so we can unconditionally remove the ability.
mAppForAllowingBgActivityStartsByStart
- .removeAllowBackgroundActivityStartsToken(ServiceRecord.this);
+ .removeBackgroundStartPrivileges(ServiceRecord.this);
}
mAppForAllowingBgActivityStartsByStart = null;
}
@@ -999,8 +1011,8 @@
ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT);
}
- private void setAllowedBgActivityStartsByStart(boolean newValue) {
- mIsAllowedBgActivityStartsByStart = newValue;
+ private void setAllowedBgActivityStartsByStart(BackgroundStartPrivileges newValue) {
+ mBackgroundStartPrivilegesByStartMerged = newValue;
updateParentProcessBgActivityStartsToken();
}
@@ -1011,46 +1023,42 @@
* {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord
* should be contributing as a token in parent ProcessRecord.
*
- * @see com.android.server.am.ProcessRecord#addOrUpdateAllowBackgroundActivityStartsToken(
- * Binder, IBinder)
- * @see com.android.server.am.ProcessRecord#removeAllowBackgroundActivityStartsToken(Binder)
+ * @see com.android.server.am.ProcessRecord#addOrUpdateBackgroundStartPrivileges(Binder,
+ * BackgroundStartPrivileges)
+ * @see com.android.server.am.ProcessRecord#removeBackgroundStartPrivileges(Binder)
*/
private void updateParentProcessBgActivityStartsToken() {
if (app == null) {
return;
}
- if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) {
+ if (mBackgroundStartPrivilegesByStartMerged.allowsAny()
+ || mIsAllowedBgActivityStartsByBinding) {
// if the token is already there it's safe to "re-add it" - we're dealing with
// a set of Binder objects
- app.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken());
+ app.addOrUpdateBackgroundStartPrivileges(this,
+ getBackgroundStartPrivilegesWithExclusiveToken());
} else {
- app.removeAllowBackgroundActivityStartsToken(this);
+ app.removeBackgroundStartPrivileges(this);
}
}
/**
- * Returns the originating token if that's the only reason background activity starts are
- * allowed. In order for that to happen the service has to be allowed only due to starts, since
- * bindings are not associated with originating tokens, and all the start tokens have to be the
- * same and there can't be any null originating token in the queue.
+ * Returns {@link BackgroundStartPrivileges} that represents the privileges a specific
+ * originating token or a generic aggregate token.
*
- * Originating tokens are optional, so the caller could provide null when it allows bg activity
- * starts.
+ * If all privileges are associated with the same token (i.e. the service is only allowed due
+ * to starts) the token will be retained, otherwise (e.g. the privileges were granted by
+ * bindings) the originating token will be empty.
*/
@Nullable
- private IBinder getExclusiveOriginatingToken() {
- if (mIsAllowedBgActivityStartsByBinding
- || mBgActivityStartsByStartOriginatingTokens.isEmpty()) {
- return null;
+ private BackgroundStartPrivileges getBackgroundStartPrivilegesWithExclusiveToken() {
+ if (mIsAllowedBgActivityStartsByBinding) {
+ return BackgroundStartPrivileges.ALLOW_BAL;
}
- IBinder firstToken = mBgActivityStartsByStartOriginatingTokens.get(0);
- for (int i = 1, n = mBgActivityStartsByStartOriginatingTokens.size(); i < n; i++) {
- IBinder token = mBgActivityStartsByStartOriginatingTokens.get(i);
- if (token != firstToken) {
- return null;
- }
+ if (mBackgroundStartPrivilegesByStart.isEmpty()) {
+ return BackgroundStartPrivileges.NONE;
}
- return firstToken;
+ return mBackgroundStartPrivilegesByStartMerged;
}
@GuardedBy("ams")
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 234eec3..f61737e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2742,6 +2742,12 @@
return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
}
+ Pair<Integer, Integer> getCurrentAndTargetUserIds() {
+ synchronized (mLock) {
+ return new Pair<>(mCurrentUserId, mTargetUserId);
+ }
+ }
+
@GuardedBy("mLock")
private int getCurrentUserIdLU() {
return mCurrentUserId;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 58ddd9c..c794b04 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3733,18 +3733,6 @@
}
}
- // TODO enforce MODIFY_AUDIO_SYSTEM_SETTINGS when defined
- private void enforceModifyAudioRoutingOrSystemSettingsPermission() {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- != PackageManager.PERMISSION_GRANTED
- /*&& mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
- != PackageManager.PERMISSION_DENIED*/) {
- throw new SecurityException(
- "Missing MODIFY_AUDIO_ROUTING or MODIFY_AUDIO_SYSTEM_SETTINGS permission");
- }
- }
-
private void enforceAccessUltrasoundPermission() {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3785,12 +3773,13 @@
super.setVolumeIndexForAttributes_enforcePermission();
Objects.requireNonNull(attr, "attr must not be null");
- final int volumeGroup = getVolumeGroupIdForAttributes(attr);
+ int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
+ attr, /* fallbackOnDefault= */false);
if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
Log.e(TAG, ": no volume group found for attributes " + attr.toString());
return;
}
- final VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
+ VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(),
index/*val1*/, flags/*val2*/, callingPackage));
@@ -3798,7 +3787,7 @@
vgs.setVolumeIndex(index, flags);
// For legacy reason, propagate to all streams associated to this volume group
- for (final int groupedStream : vgs.getLegacyStreamTypes()) {
+ for (int groupedStream : vgs.getLegacyStreamTypes()) {
try {
ensureValidStreamType(groupedStream);
} catch (IllegalArgumentException e) {
@@ -3830,7 +3819,9 @@
super.getVolumeIndexForAttributes_enforcePermission();
Objects.requireNonNull(attr, "attr must not be null");
- final int volumeGroup = getVolumeGroupIdForAttributes(attr);
+ final int volumeGroup =
+ AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
+ attr, /* fallbackOnDefault= */false);
if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
throw new IllegalArgumentException("No volume group for attributes " + attr);
}
@@ -3856,13 +3847,16 @@
return AudioSystem.getMinVolumeIndexForAttributes(attr);
}
+ @Override
+ @android.annotation.EnforcePermission(anyOf =
+ {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
/** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
* Part of service interface, check permissions and parameters here
* Note calling package is for logging purposes only, not to be trusted
*/
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada,
@NonNull String callingPackage) {
- enforceModifyAudioRoutingOrSystemSettingsPermission();
+ super.setDeviceVolume_enforcePermission();
Objects.requireNonNull(vi);
Objects.requireNonNull(ada);
Objects.requireNonNull(callingPackage);
@@ -4380,31 +4374,6 @@
sendVolumeUpdate(streamType, oldIndex, index, flags, device);
}
-
-
- private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
- Objects.requireNonNull(attributes, "attributes must not be null");
- int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes);
- if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
- return volumeGroupId;
- }
- // The default volume group is the one hosted by default product strategy, i.e.
- // supporting Default Attributes
- return getVolumeGroupIdForAttributesInt(AudioProductStrategy.getDefaultAttributes());
- }
-
- private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) {
- Objects.requireNonNull(attributes, "attributes must not be null");
- for (final AudioProductStrategy productStrategy :
- AudioProductStrategy.getAudioProductStrategies()) {
- int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
- if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
- return volumeGroupId;
- }
- }
- return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
- }
-
private void dispatchAbsoluteVolumeChanged(int streamType, AbsoluteVolumeDeviceInfo deviceInfo,
int index) {
VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType);
@@ -4437,7 +4406,6 @@
}
}
-
// No ringer or zen muted stream volumes can be changed unless it'll exit dnd
private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
switch (mNm.getZenMode()) {
@@ -4828,12 +4796,15 @@
}
}
+ @Override
+ @android.annotation.EnforcePermission(anyOf =
+ {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SYSTEM_SETTINGS"})
/**
* @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes)
*/
public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
@NonNull AudioDeviceAttributes ada, @NonNull String callingPackage) {
- enforceModifyAudioRoutingOrSystemSettingsPermission();
+ super.getDeviceVolume_enforcePermission();
Objects.requireNonNull(vi);
Objects.requireNonNull(ada);
Objects.requireNonNull(callingPackage);
diff --git a/services/core/java/com/android/server/backup/AppGrammaticalGenderBackupHelper.java b/services/core/java/com/android/server/backup/AppGrammaticalGenderBackupHelper.java
new file mode 100644
index 0000000..9e8db6e
--- /dev/null
+++ b/services/core/java/com/android/server/backup/AppGrammaticalGenderBackupHelper.java
@@ -0,0 +1,66 @@
+/*
+ * 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.backup;
+
+import static android.app.backup.BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+
+import android.annotation.UserIdInt;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BlobBackupHelper;
+import android.os.ParcelFileDescriptor;
+
+import com.android.server.LocalServices;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
+
+public class AppGrammaticalGenderBackupHelper extends BlobBackupHelper {
+ private static final int BLOB_VERSION = 1;
+ private static final String KEY_APP_GENDER = "app_gender";
+
+ private final @UserIdInt int mUserId;
+ private final GrammaticalInflectionManagerInternal mGrammarInflectionManagerInternal;
+
+ public AppGrammaticalGenderBackupHelper(int userId) {
+ super(BLOB_VERSION, KEY_APP_GENDER);
+ mUserId = userId;
+ mGrammarInflectionManagerInternal = LocalServices.getService(
+ GrammaticalInflectionManagerInternal.class);
+ }
+
+ @Override
+ public void performBackup(ParcelFileDescriptor oldStateFd, BackupDataOutput data,
+ ParcelFileDescriptor newStateFd) {
+ // Only backup the gender data if e2e encryption is present
+ if ((data.getTransportFlags() & FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED) == 0) {
+ return;
+ }
+
+ super.performBackup(oldStateFd, data, newStateFd);
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ return KEY_APP_GENDER.equals(key) && mGrammarInflectionManagerInternal != null ?
+ mGrammarInflectionManagerInternal.getBackupPayload(mUserId) : null;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ if (KEY_APP_GENDER.equals(key) && mGrammarInflectionManagerInternal != null) {
+ mGrammarInflectionManagerInternal.stageAndApplyRestoredPayload(payload, mUserId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index 59d8afa..b18be3c 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -58,6 +58,7 @@
private static final String SLICES_HELPER = "slices";
private static final String PEOPLE_HELPER = "people";
private static final String APP_LOCALES_HELPER = "app_locales";
+ private static final String APP_GENDER_HELPER = "app_gender";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -105,6 +106,7 @@
addHelper(SLICES_HELPER, new SliceBackupHelper(this));
addHelper(PEOPLE_HELPER, new PeopleBackupHelper(mUserId));
addHelper(APP_LOCALES_HELPER, new AppSpecificLocalesBackupHelper(mUserId));
+ addHelper(APP_GENDER_HELPER, new AppGrammaticalGenderBackupHelper(mUserId));
}
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index dcc98e1..5b696c2 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -104,6 +104,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
@@ -264,6 +265,8 @@
private final SyncLogger mLogger;
+ private final AppCloningDeviceConfigHelper mAppCloningDeviceConfigHelper;
+
private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
for (int i = 0, size = pendingJobs.size(); i < size; i++) {
JobInfo job = pendingJobs.get(i);
@@ -627,6 +630,7 @@
}, mSyncHandler);
mConstants = new SyncManagerConstants(context);
+ mAppCloningDeviceConfigHelper = AppCloningDeviceConfigHelper.getInstance(context);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -828,6 +832,18 @@
}
/**
+ * Check whether the feature flag controlling contacts sharing for clone profile is set. If
+ * true, the contact syncs for clone profile should be disabled.
+ *
+ * @return true/false if contact sharing is enabled/disabled
+ */
+ protected boolean isContactSharingAllowedForCloneProfile() {
+ // TODO(b/253449368): This method should also check for the config controlling
+ // all app-cloning features.
+ return mAppCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks();
+ }
+
+ /**
* Check if account sync should be disabled for the given user and provider.
* @param userInfo
* @param providerName
@@ -836,7 +852,9 @@
*/
@VisibleForTesting
protected boolean shouldDisableSyncForUser(UserInfo userInfo, String providerName) {
- if (userInfo == null || providerName == null) return false;
+ if (userInfo == null || providerName == null || !isContactSharingAllowedForCloneProfile()) {
+ return false;
+ }
return providerName.equals(ContactsContract.AUTHORITY)
&& !areContactWritesEnabledForUser(userInfo);
}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
new file mode 100644
index 0000000..5be0735
--- /dev/null
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
@@ -0,0 +1,193 @@
+/*
+ * 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.grammaticalinflection;
+
+import android.app.backup.BackupManager;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.time.Clock;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GrammaticalInflectionBackupHelper {
+ private static final String TAG = GrammaticalInflectionBackupHelper.class.getSimpleName();
+ private static final String SYSTEM_BACKUP_PACKAGE_KEY = "android";
+ // Stage data would be deleted on reboot since it's stored in memory. So it's retained until
+ // retention period OR next reboot, whichever happens earlier.
+ private static final Duration STAGE_DATA_RETENTION_PERIOD = Duration.ofDays(3);
+
+ private final SparseArray<StagedData> mCache = new SparseArray<>();
+ private final Object mCacheLock = new Object();
+ private final PackageManager mPackageManager;
+ private final GrammaticalInflectionService mGrammaticalGenderService;
+ private final Clock mClock;
+
+ static class StagedData {
+ final long mCreationTimeMillis;
+ final HashMap<String, Integer> mPackageStates;
+
+ StagedData(long creationTimeMillis) {
+ mCreationTimeMillis = creationTimeMillis;
+ mPackageStates = new HashMap<>();
+ }
+ }
+
+ public GrammaticalInflectionBackupHelper(GrammaticalInflectionService grammaticalGenderService,
+ PackageManager packageManager) {
+ mGrammaticalGenderService = grammaticalGenderService;
+ mPackageManager = packageManager;
+ mClock = Clock.systemUTC();
+ }
+
+ public byte[] getBackupPayload(int userId) {
+ synchronized (mCacheLock) {
+ cleanStagedDataForOldEntries();
+ }
+
+ HashMap<String, Integer> pkgGenderInfo = new HashMap<>();
+ for (ApplicationInfo appInfo : mPackageManager.getInstalledApplicationsAsUser(
+ PackageManager.ApplicationInfoFlags.of(0), userId)) {
+ int gender = mGrammaticalGenderService.getApplicationGrammaticalGender(
+ appInfo.packageName, userId);
+ if (gender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ pkgGenderInfo.put(appInfo.packageName, gender);
+ }
+ }
+
+ if (!pkgGenderInfo.isEmpty()) {
+ return convertToByteArray(pkgGenderInfo);
+ } else {
+ return null;
+ }
+ }
+
+ public void stageAndApplyRestoredPayload(byte[] payload, int userId) {
+ synchronized (mCacheLock) {
+ cleanStagedDataForOldEntries();
+
+ HashMap<String, Integer> pkgInfo = readFromByteArray(payload);
+ if (pkgInfo.isEmpty()) {
+ return;
+ }
+
+ StagedData stagedData = new StagedData(mClock.millis());
+ for (Map.Entry<String, Integer> info : pkgInfo.entrySet()) {
+ // If app installed, restore immediately, otherwise put it in cache.
+ if (isPackageInstalledForUser(info.getKey(), userId)) {
+ if (!hasSetBeforeRestoring(info.getKey(), userId)) {
+ mGrammaticalGenderService.setRequestedApplicationGrammaticalGender(
+ info.getKey(), userId, info.getValue());
+ }
+ } else {
+ if (info.getValue() != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ stagedData.mPackageStates.put(info.getKey(), info.getValue());
+ }
+ }
+ }
+
+ mCache.append(userId, stagedData);
+ }
+ }
+
+ private boolean hasSetBeforeRestoring(String pkgName, int userId) {
+ return mGrammaticalGenderService.getApplicationGrammaticalGender(pkgName, userId)
+ != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ }
+
+ public void onPackageAdded(String packageName, int uid) {
+ synchronized (mCacheLock) {
+ int userId = UserHandle.getUserId(uid);
+ StagedData cache = mCache.get(userId);
+ if (cache != null && cache.mPackageStates.containsKey(packageName)) {
+ int grammaticalGender = cache.mPackageStates.get(packageName);
+ if (grammaticalGender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ mGrammaticalGenderService.setRequestedApplicationGrammaticalGender(
+ packageName, userId, grammaticalGender);
+ }
+ }
+ }
+ }
+
+ public void onPackageDataCleared() {
+ notifyBackupManager();
+ }
+
+ public void onPackageRemoved() {
+ notifyBackupManager();
+ }
+
+ public static void notifyBackupManager() {
+ BackupManager.dataChanged(SYSTEM_BACKUP_PACKAGE_KEY);
+ }
+
+ private byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) {
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final ObjectOutputStream objStream = new ObjectOutputStream(out)) {
+ objStream.writeObject(pkgGenderInfo);
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.e(TAG, "cannot convert payload to byte array.", e);
+ return null;
+ }
+ }
+
+ private HashMap<String, Integer> readFromByteArray(byte[] payload) {
+ HashMap<String, Integer> data = new HashMap<>();
+
+ try (ByteArrayInputStream byteIn = new ByteArrayInputStream(payload);
+ ObjectInputStream in = new ObjectInputStream(byteIn)) {
+ data = (HashMap<String, Integer>) in.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ Log.e(TAG, "cannot convert payload to HashMap.", e);
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ private void cleanStagedDataForOldEntries() {
+ for (int i = 0; i < mCache.size(); i++) {
+ int userId = mCache.keyAt(i);
+ StagedData stagedData = mCache.get(userId);
+ if (stagedData.mCreationTimeMillis
+ < mClock.millis() - STAGE_DATA_RETENTION_PERIOD.toMillis()) {
+ mCache.remove(userId);
+ }
+ }
+ }
+
+ private boolean isPackageInstalledForUser(String packageName, int userId) {
+ PackageInfo pkgInfo = null;
+ try {
+ pkgInfo = mPackageManager.getPackageInfoAsUser(packageName, /* flags= */ 0, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // The package is not installed
+ }
+ return pkgInfo != null;
+ }
+}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
new file mode 100644
index 0000000..1f59b57
--- /dev/null
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
@@ -0,0 +1,41 @@
+/*
+ * 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.grammaticalinflection;
+
+import android.annotation.Nullable;
+
+/**
+ * System-server internal interface to the {@link android.app.GrammaticalInflectionManager}.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class GrammaticalInflectionManagerInternal {
+ /**
+ * Returns the app-gender to be backed up as a data-blob.
+ */
+ public abstract @Nullable byte[] getBackupPayload(int userId);
+
+ /**
+ * Restores the app-gender that were previously backed up.
+ *
+ * <p>This method will parse the input data blob and restore the gender for apps which are
+ * present on the device. It will stage the gender data for the apps which are not installed
+ * at the time this is called, to be referenced later when the app is installed.
+ */
+ public abstract void stageAndApplyRestoredPayload(byte[] payload, int userId);
+}
+
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionPackageMonitor.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionPackageMonitor.java
new file mode 100644
index 0000000..268bf66
--- /dev/null
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionPackageMonitor.java
@@ -0,0 +1,42 @@
+/*
+ * 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.grammaticalinflection;
+
+import com.android.internal.content.PackageMonitor;
+
+public class GrammaticalInflectionPackageMonitor extends PackageMonitor {
+ private GrammaticalInflectionBackupHelper mBackupHelper;
+
+ GrammaticalInflectionPackageMonitor(GrammaticalInflectionBackupHelper backupHelper) {
+ mBackupHelper = backupHelper;
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ mBackupHelper.onPackageAdded(packageName, uid);
+ }
+
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ mBackupHelper.onPackageDataCleared();
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ mBackupHelper.onPackageRemoved();
+ }
+}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 6cfe921..1a357ee 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -18,9 +18,12 @@
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
+import android.annotation.Nullable;
import android.app.IGrammaticalInflectionManager;
import android.content.Context;
+import android.os.Binder;
import android.os.IBinder;
+import android.os.Process;
import android.os.SystemProperties;
import com.android.server.LocalServices;
@@ -34,6 +37,7 @@
*/
public class GrammaticalInflectionService extends SystemService {
+ private final GrammaticalInflectionBackupHelper mBackupHelper;
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private static final String GRAMMATICAL_INFLECTION_ENABLED =
"i18n.grammatical_Inflection.enabled";
@@ -46,17 +50,20 @@
* </p>
*
* @param context The system server context.
- *
* @hide
*/
public GrammaticalInflectionService(Context context) {
super(context);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mBackupHelper = new GrammaticalInflectionBackupHelper(
+ this, context.getPackageManager());
}
@Override
public void onStart() {
publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mService);
+ LocalServices.addService(GrammaticalInflectionManagerInternal.class,
+ new GrammaticalInflectionManagerInternalImpl());
}
private final IBinder mService = new IGrammaticalInflectionManager.Stub() {
@@ -68,7 +75,40 @@
}
};
- private void setRequestedApplicationGrammaticalGender(
+ private final class GrammaticalInflectionManagerInternalImpl
+ extends GrammaticalInflectionManagerInternal {
+
+ @Override
+ @Nullable
+ public byte[] getBackupPayload(int userId) {
+ checkCallerIsSystem();
+ return mBackupHelper.getBackupPayload(userId);
+ }
+
+ @Override
+ public void stageAndApplyRestoredPayload(byte[] payload, int userId) {
+ mBackupHelper.stageAndApplyRestoredPayload(payload, userId);
+ }
+
+ private void checkCallerIsSystem() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Caller is not system.");
+ }
+ }
+ }
+
+ protected int getApplicationGrammaticalGender(String appPackageName, int userId) {
+ final ActivityTaskManagerInternal.PackageConfig appConfig =
+ mActivityTaskManagerInternal.getApplicationConfig(appPackageName, userId);
+
+ if (appConfig == null || appConfig.mGrammaticalGender == null) {
+ return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ } else {
+ return appConfig.mGrammaticalGender;
+ }
+ }
+
+ protected void setRequestedApplicationGrammaticalGender(
String appPackageName, int userId, int gender) {
if (!SystemProperties.getBoolean(GRAMMATICAL_INFLECTION_ENABLED, true)) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index e21895a..35434b7 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -136,14 +136,14 @@
@ImeVisibilityStateComputer.VisibilityState int state, int reason) {
switch (state) {
case STATE_SHOW_IME:
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
// Send to window manager to show IME after IME layout finishes.
mWindowManagerInternal.showImePostLayout(windowToken, statsToken);
break;
case STATE_HIDE_IME:
if (mService.mCurFocusedWindowClient != null) {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
// IMMS only knows of focused window, not the actual IME target.
// e.g. it isn't aware of any window that has both
@@ -154,7 +154,7 @@
mWindowManagerInternal.hideIme(windowToken,
mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
}
break;
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 795e4bf..10c16b6 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -182,10 +182,10 @@
*/
boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken, int showFlags) {
if (mPolicy.mA11yRequestingNoSoftKeyboard || mPolicy.mImeHiddenByDisplayPolicy) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
if ((showFlags & InputMethodManager.SHOW_FORCED) != 0) {
mRequestedShowExplicitly = true;
mShowForced = true;
@@ -206,15 +206,15 @@
if ((hideFlags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mRequestedShowExplicitly || mShowForced)) {
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
return false;
}
if (mShowForced && (hideFlags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
return true;
}
@@ -380,7 +380,12 @@
}
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
- // Do nothing.
+ // Do nothing but preserving the last IME requested visibility state.
+ final ImeTargetWindowState lastState =
+ getWindowStateOrNull(mService.mLastImeTargetWindow);
+ if (lastState != null) {
+ state.setRequestedImeVisible(lastState.mRequestedImeVisible);
+ }
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
if (isForwardNavigation) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 187de930..ba9e280 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -469,11 +469,11 @@
@GuardedBy("ImfLock.class")
private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
- if (getCurIntent() == null || conn == null) {
+ if (mCurIntent == null || conn == null) {
Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
return false;
}
- return mContext.bindServiceAsUser(getCurIntent(), conn, flags,
+ return mContext.bindServiceAsUser(mCurIntent, conn, flags,
new UserHandle(mSettings.getCurrentUserId()));
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 19108a8..ce3abfd 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2290,7 +2290,7 @@
mCurClient.mSessionRequestedForAccessibility = false;
mCurClient = null;
mCurVirtualDisplayToScreenMatrix = null;
- ImeTracker.get().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+ ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = null;
mMenuController.hideInputMethodMenuLocked();
@@ -3276,7 +3276,8 @@
"InputMethodManagerService#showSoftInput");
synchronized (ImfLock.class) {
if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
return false;
}
final long ident = Binder.clearCallingIdentity();
@@ -3349,15 +3350,16 @@
@BinderThread
@Override
public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
- Objects.requireNonNull(windowToken, "windowToken must not be null");
- synchronized (ImfLock.class) {
- if (mCurFocusedWindow != windowToken || mCurPerceptible == perceptible) {
- return;
+ Binder.withCleanCallingIdentity(() -> {
+ Objects.requireNonNull(windowToken, "windowToken must not be null");
+ synchronized (ImfLock.class) {
+ if (mCurFocusedWindow != windowToken || mCurPerceptible == perceptible) {
+ return;
+ }
+ mCurPerceptible = perceptible;
+ updateSystemUiLocked();
}
- mCurPerceptible = perceptible;
- Binder.withCleanCallingIdentity(() ->
- updateSystemUiLocked(mImeWindowVis, mBackDisposition));
- }
+ });
}
@GuardedBy("ImfLock.class")
@@ -3376,7 +3378,7 @@
// TODO(b/261565259): to avoid using null, add package name in ClientState
final String packageName = (mCurEditorInfo != null) ? mCurEditorInfo.packageName : null;
final int uid = mCurClient != null ? mCurClient.mUid : -1;
- statsToken = ImeTracker.get().onRequestShow(packageName, uid,
+ statsToken = ImeTracker.forLogging().onRequestShow(packageName, uid,
ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
}
@@ -3385,19 +3387,19 @@
}
if (!mSystemReady) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
mVisibilityStateComputer.requestImeVisibility(windowToken, true);
// Ensure binding the connection when IME is going to show.
mBindingController.setCurrentMethodVisible();
final IInputMethodInvoker curMethod = getCurMethodLocked();
- ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+ ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
if (curMethod != null) {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
mCurStatsToken = null;
if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) {
@@ -3408,7 +3410,7 @@
mVisibilityStateComputer.setInputShown(true);
return true;
} else {
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = statsToken;
}
return false;
@@ -3424,9 +3426,10 @@
synchronized (ImfLock.class) {
if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
if (isInputShown()) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+ ImeTracker.forLogging().onFailed(
+ statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
} else {
- ImeTracker.get().onCancelled(statsToken,
+ ImeTracker.forLogging().onCancelled(statsToken,
ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
}
return false;
@@ -3459,7 +3462,7 @@
} else {
uid = -1;
}
- statsToken = ImeTracker.get().onRequestHide(packageName, uid,
+ statsToken = ImeTracker.forLogging().onRequestHide(packageName, uid,
ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason);
}
@@ -3485,15 +3488,15 @@
// delivered to the IME process as an IPC. Hence the inconsistency between
// IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
// the final state.
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
mVisibilityApplier.performHideIme(windowToken, statsToken, resultReceiver, reason);
} else {
- ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
+ ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
}
mBindingController.setCurrentMethodNotVisible();
mVisibilityStateComputer.clearImeShowFlags();
// Cancel existing statsToken for show IME as we got a hide request.
- ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+ ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = null;
return shouldHideSoftInput;
}
@@ -3765,16 +3768,16 @@
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
if (!isImeClientFocused(mCurFocusedWindow, cs)) {
Slog.w(TAG, String.format("Ignoring %s of uid %d : %s", methodName, uid, client));
return false;
}
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
return true;
}
@@ -4551,7 +4554,8 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
return;
}
final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(windowToken);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 434c0d7..de3a7ef 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -533,11 +533,6 @@
if (userId == USER_FRP) {
return null;
}
-
- if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
- key = Settings.Secure.LOCK_PATTERN_ENABLED;
- }
-
return readKeyValue(key, defaultValue, userId);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index cde4ea9..ffc309e 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -64,7 +64,6 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -93,8 +92,6 @@
// in MediaRouter2, remove this constant and replace the usages with the real request IDs.
private static final long DUMMY_REQUEST_ID = -1;
- private static final int DUMP_EVENTS_MAX_COUNT = 70;
-
private static final String MEDIA_BETTER_TOGETHER_NAMESPACE = "media_better_together";
private static final String KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE =
@@ -121,9 +118,6 @@
@GuardedBy("mLock")
private int mCurrentActiveUserId = -1;
- private final EventLogger mEventLogger =
- new EventLogger(DUMP_EVENTS_MAX_COUNT, "MediaRouter2ServiceImpl");
-
private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
(uid, importance) -> {
synchronized (mLock) {
@@ -689,16 +683,14 @@
} else {
pw.println(indent + " <no user records>");
}
- mEventLogger.dump(pw, indent);
}
}
/* package */ void updateRunningUserAndProfiles(int newActiveUserId) {
synchronized (mLock) {
if (mCurrentActiveUserId != newActiveUserId) {
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("switchUser",
- "userId: %d", newActiveUserId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "switchUser | user: %d", newActiveUserId));
mCurrentActiveUserId = newActiveUserId;
// disposeUserIfNeededLocked might modify the collection, hence clone
@@ -771,8 +763,8 @@
obtainMessage(UserHandler::notifyRouterRegistered,
userRecord.mHandler, routerRecord));
- mEventLogger.enqueue(EventLogger.StringEvent.from("registerRouter2",
- "package: %s, uid: %d, pid: %d, router id: %d",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerRouter2 | package: %s, uid: %d, pid: %d, router: %d",
packageName, uid, pid, routerRecord.mRouterId));
}
@@ -784,12 +776,10 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from(
- "unregisterRouter2",
- "package: %s, router id: %d",
- routerRecord.mPackageName,
- routerRecord.mRouterId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterRouter2 | package: %s, router: %d",
+ routerRecord.mPackageName,
+ routerRecord.mRouterId));
UserRecord userRecord = routerRecord.mUserRecord;
userRecord.mRouterRecords.remove(routerRecord);
@@ -816,9 +806,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "setDiscoveryRequestWithRouter2",
- "router id: %d, discovery request: %s",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setDiscoveryRequestWithRouter2 | router: %d, discovery request: %s",
routerRecord.mRouterId, discoveryRequest.toString()));
routerRecord.mDiscoveryPreference = discoveryRequest;
@@ -842,12 +831,11 @@
.map(RouteListingPreference.Item::getRouteId)
.collect(Collectors.joining(","))
: null;
- mEventLogger.enqueue(
- EventLogger.StringEvent.from(
- "setRouteListingPreference",
- "router id: %d, route listing preference: [%s]",
- routerRecord.mRouterId,
- routeListingAsString));
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteListingPreference | router: %d, route listing preference: [%s]",
+ routerRecord.mRouterId,
+ routeListingAsString));
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(
@@ -863,9 +851,8 @@
RouterRecord routerRecord = mAllRouterRecords.get(binder);
if (routerRecord != null) {
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "setRouteVolumeWithRouter2",
- "router id: %d, volume: %d",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithRouter2 | router: %d, volume: %d",
routerRecord.mRouterId, volume));
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -948,9 +935,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "selectRouteWithRouter2",
- "router id: %d, route: %s",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithRouter2 | router: %d, route: %s",
routerRecord.mRouterId, route.getId()));
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -968,9 +954,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "deselectRouteWithRouter2",
- "router id: %d, route: %s",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithRouter2 | router: %d, route: %s",
routerRecord.mRouterId, route.getId()));
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -988,9 +973,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "transferToRouteWithRouter2",
- "router id: %d, route: %s",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithRouter2 | router: %d, route: %s",
routerRecord.mRouterId, route.getId()));
String defaultRouteId =
@@ -1018,9 +1002,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "setSessionVolumeWithRouter2",
- "router id: %d, session: %s, volume: %d",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d",
routerRecord.mRouterId, uniqueSessionId, volume));
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -1038,9 +1021,8 @@
return;
}
- mEventLogger.enqueue(EventLogger.StringEvent.from(
- "releaseSessionWithRouter2",
- "router id: %d, session: %s",
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithRouter2 | router: %d, session: %s",
routerRecord.mRouterId, uniqueSessionId));
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -1084,10 +1066,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("registerManager",
- "uid: %d, pid: %d, package: %s, userId: %d",
- uid, pid, packageName, userId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerManager | uid: %d, pid: %d, package: %s, user: %d",
+ uid, pid, packageName, userId));
mContext.enforcePermission(Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid,
"Must hold MEDIA_CONTENT_CONTROL permission.");
@@ -1135,13 +1116,11 @@
}
UserRecord userRecord = managerRecord.mUserRecord;
- mEventLogger.enqueue(
- EventLogger.StringEvent.from(
- "unregisterManager",
- "package: %s, userId: %d, managerId: %d",
- managerRecord.mPackageName,
- userRecord.mUserId,
- managerRecord.mManagerId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterManager | package: %s, user: %d, manager: %d",
+ managerRecord.mPackageName,
+ userRecord.mUserId,
+ managerRecord.mManagerId));
userRecord.mManagerRecords.remove(managerRecord);
managerRecord.dispose();
@@ -1155,9 +1134,8 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("startScan",
- "manager: %d", managerRecord.mManagerId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "startScan | manager: %d", managerRecord.mManagerId));
managerRecord.startScan();
}
@@ -1169,9 +1147,8 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("stopScan",
- "manager: %d", managerRecord.mManagerId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "stopScan | manager: %d", managerRecord.mManagerId));
managerRecord.stopScan();
}
@@ -1186,10 +1163,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("setRouteVolumeWithManager",
- "managerId: %d, routeId: %s, volume: %d",
- managerRecord.mManagerId, route.getId(), volume));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithManager | manager: %d, route: %s, volume: %d",
+ managerRecord.mManagerId, route.getId(), volume));
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
@@ -1206,10 +1182,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("requestCreateSessionWithManager",
- "managerId: %d, routeId: %s",
- managerRecord.mManagerId, route.getId()));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "requestCreateSessionWithManager | manager: %d, route: %s",
+ managerRecord.mManagerId, route.getId()));
String packageName = oldSession.getClientPackageName();
@@ -1256,10 +1231,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("selectRouteWithManager",
- "managerId: %d, session: %s, routeId: %s",
- managerRecord.mManagerId, uniqueSessionId, route.getId()));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
@@ -1282,10 +1256,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("deselectRouteWithManager",
- "managerId: %d, session: %s, routeId: %s",
- managerRecord.mManagerId, uniqueSessionId, route.getId()));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
@@ -1308,10 +1281,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("transferToRouteWithManager",
- "managerId: %d, session: %s, routeId: %s",
- managerRecord.mManagerId, uniqueSessionId, route.getId()));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
@@ -1334,10 +1306,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("setSessionVolumeWithManager",
- "managerId: %d, session: %s, volume: %d",
- managerRecord.mManagerId, uniqueSessionId, volume));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithManager | manager: %d, session: %s, volume: %d",
+ managerRecord.mManagerId, uniqueSessionId, volume));
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
@@ -1355,10 +1326,9 @@
return;
}
- mEventLogger.enqueue(
- EventLogger.StringEvent.from("releaseSessionWithManager",
- "managerId: %d, session: %s",
- managerRecord.mManagerId, uniqueSessionId));
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithManager | manager: %d, session: %s",
+ managerRecord.mManagerId, uniqueSessionId));
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1791,8 +1761,7 @@
MediaRoute2ProviderInfo oldInfo =
providerInfoIndex == -1 ? null : mLastProviderInfos.get(providerInfoIndex);
MediaRouter2ServiceImpl mediaRouter2Service = mServiceRef.get();
- EventLogger eventLogger =
- mediaRouter2Service != null ? mediaRouter2Service.mEventLogger : null;
+
if (oldInfo == newInfo) {
// Nothing to do.
return;
@@ -1854,23 +1823,21 @@
}
}
- if (eventLogger != null) {
- if (!addedRoutes.isEmpty()) {
- // If routes were added, newInfo cannot be null.
- eventLogger.enqueue(
- toLoggingEvent(
- /* source= */ "addProviderRoutes",
- newInfo.getUniqueId(),
- addedRoutes));
- }
- if (!removedRoutes.isEmpty()) {
- // If routes were removed, oldInfo cannot be null.
- eventLogger.enqueue(
- toLoggingEvent(
- /* source= */ "removeProviderRoutes",
- oldInfo.getUniqueId(),
- removedRoutes));
- }
+ if (!addedRoutes.isEmpty()) {
+ // If routes were added, newInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "addProviderRoutes",
+ newInfo.getUniqueId(),
+ addedRoutes));
+ }
+ if (!removedRoutes.isEmpty()) {
+ // If routes were removed, oldInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "removeProviderRoutes",
+ oldInfo.getUniqueId(),
+ removedRoutes));
}
dispatchUpdates(
@@ -1880,14 +1847,14 @@
mSystemProvider.getDefaultRoute());
}
- private static EventLogger.Event toLoggingEvent(
+ private static String toLoggingMessage(
String source, String providerId, ArrayList<MediaRoute2Info> routes) {
String routesString =
routes.stream()
.map(it -> String.format("%s | %s", it.getOriginalId(), it.getName()))
.collect(Collectors.joining(/* delimiter= */ ", "));
- return EventLogger.StringEvent.from(
- source, "provider: %s, routes: [%s]", providerId, routesString);
+ return TextUtils.formatSimple("%s | provider: %s, routes: [%s]",
+ source, providerId, routesString);
}
/**
diff --git a/services/core/java/com/android/server/media/projection/TEST_MAPPING b/services/core/java/com/android/server/media/projection/TEST_MAPPING
new file mode 100644
index 0000000..a792498
--- /dev/null
+++ b/services/core/java/com/android/server/media/projection/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "MediaProjectionTests",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 5ab9f38..69ea559 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -108,7 +108,7 @@
@VisibleForTesting
static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
@VisibleForTesting
- static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 50000;
+ static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 6000;
private static final int NOTIFICATION_PREFERENCES_PULL_LIMIT = 1000;
private static final int NOTIFICATION_CHANNEL_PULL_LIMIT = 2000;
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2752104..c2f0f52 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -766,7 +766,7 @@
*/
crossProfileResults = mCrossProfileIntentResolverEngine.resolveIntent(this, intent,
resolvedType, userId, flags, pkgName, hasNonNegativePriorityResult,
- mSettings::getPackage);
+ resolveForStart, mSettings::getPackage);
if (intent.hasWebURI() || !crossProfileResults.isEmpty()) sortResult = true;
} else {
final PackageStateInternal setting =
@@ -791,7 +791,7 @@
*/
crossProfileResults = mCrossProfileIntentResolverEngine.resolveIntent(this, intent,
resolvedType, userId, flags, pkgName, false,
- mSettings::getPackage);
+ resolveForStart, mSettings::getPackage);
}
/*
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
index 397fdd8..e149b04 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
@@ -84,15 +84,16 @@
* @param pkgName the application package name this Intent is limited to.
* @param hasNonNegativePriorityResult signifies if current profile have any non-negative(active
* and valid) ResolveInfo in current profile.
+ * @param resolveForStart true if resolution occurs to start an activity.
* @param pkgSettingFunction function to find PackageStateInternal for given package
* @return list of {@link CrossProfileDomainInfo} from linked profiles.
*/
public List<CrossProfileDomainInfo> resolveIntent(@NonNull Computer computer, Intent intent,
String resolvedType, int userId, long flags, String pkgName,
- boolean hasNonNegativePriorityResult,
+ boolean hasNonNegativePriorityResult, boolean resolveForStart,
Function<String, PackageStateInternal> pkgSettingFunction) {
return resolveIntentInternal(computer, intent, resolvedType, userId, userId, flags, pkgName,
- hasNonNegativePriorityResult, pkgSettingFunction, null);
+ hasNonNegativePriorityResult, resolveForStart, pkgSettingFunction, null);
}
/**
@@ -113,13 +114,14 @@
* @param pkgName the application package name this Intent is limited to.
* @param hasNonNegativePriorityResult signifies if current profile have any non-negative(active
* and valid) ResolveInfo in current profile.
+ * @param resolveForStart true if resolution occurs to start an activity.
* @param pkgSettingFunction function to find PackageStateInternal for given package
* @param visitedUserIds users for which we have already performed resolution
* @return list of {@link CrossProfileDomainInfo} from linked profiles.
*/
private List<CrossProfileDomainInfo> resolveIntentInternal(@NonNull Computer computer,
Intent intent, String resolvedType, int sourceUserId, int userId, long flags,
- String pkgName, boolean hasNonNegativePriorityResult,
+ String pkgName, boolean hasNonNegativePriorityResult, boolean resolveForStart,
Function<String, PackageStateInternal> pkgSettingFunction,
Set<Integer> visitedUserIds) {
@@ -184,7 +186,8 @@
// Choosing strategy based on source and target user
CrossProfileResolver crossProfileResolver =
- chooseCrossProfileResolver(computer, userId, targetUserId);
+ chooseCrossProfileResolver(computer, userId, targetUserId,
+ resolveForStart, flags);
/*
If {@link CrossProfileResolver} is available for source,target pair we will call it to
@@ -217,8 +220,8 @@
if (allowChainedResolution) {
crossProfileDomainInfos.addAll(resolveIntentInternal(computer, intent,
resolvedType, sourceUserId, targetUserId, flags, pkgName,
- hasNonNegativePriority(crossProfileInfos), pkgSettingFunction,
- visitedUserIds));
+ hasNonNegativePriority(crossProfileInfos), resolveForStart,
+ pkgSettingFunction, visitedUserIds));
}
}
@@ -233,18 +236,21 @@
* @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi}
* @param sourceUserId source user
* @param targetUserId target user
+ * @param resolveForStart true if resolution occurs to start an activity.
+ * @param flags used for intent resolver selection
* @return {@code CrossProfileResolver} which has value if source and target have
* strategy configured otherwise null.
*/
@SuppressWarnings("unused")
private CrossProfileResolver chooseCrossProfileResolver(@NonNull Computer computer,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
+ @UserIdInt int sourceUserId, @UserIdInt int targetUserId, boolean resolveForStart,
+ long flags) {
/**
* If source or target user is clone profile, using {@link NoFilteringResolver}
* We would return NoFilteringResolver only if it is allowed(feature flag is set).
*/
if (shouldUseNoFilteringResolver(sourceUserId, targetUserId)) {
- if (NoFilteringResolver.isIntentRedirectionAllowed()) {
+ if (NoFilteringResolver.isIntentRedirectionAllowed(mContext, resolveForStart, flags)) {
return new NoFilteringResolver(computer.getComponentResolver(),
mUserManager);
} else {
@@ -384,7 +390,6 @@
ephemeral activities.
*/
candidates = resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates);
-
return new QueryIntentActivitiesResult(computer.applyPostResolutionFilter(candidates,
instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent));
@@ -404,11 +409,10 @@
*/
candidates = filterCandidatesWithDomainPreferredActivitiesLPr(computer, intent,
matchFlags, candidates, crossProfileCandidates, userId,
- areWebInstantAppsDisabled, pkgSettingFunction);
+ areWebInstantAppsDisabled, resolveForStart, pkgSettingFunction);
} else {
candidates.addAll(resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates));
}
-
return new QueryIntentActivitiesResult(sortResult, addInstant, candidates);
}
@@ -421,13 +425,14 @@
* @param crossProfileCandidates crossProfileDomainInfos from cross profile, it have ResolveInfo
* @param userId user id of source user
* @param areWebInstantAppsDisabled true if web instant apps are disabled
+ * @param resolveForStart true if intent is for resolution
* @param pkgSettingFunction function to find PackageStateInternal for given package
* @return list of ResolveInfo
*/
private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Computer computer,
Intent intent, long matchFlags, List<ResolveInfo> candidates,
List<CrossProfileDomainInfo> crossProfileCandidates, int userId,
- boolean areWebInstantAppsDisabled,
+ boolean areWebInstantAppsDisabled, boolean resolveForStart,
Function<String, PackageStateInternal> pkgSettingFunction) {
final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
@@ -439,7 +444,7 @@
final List<ResolveInfo> result =
filterCandidatesWithDomainPreferredActivitiesLPrBody(computer, intent, matchFlags,
candidates, crossProfileCandidates, userId, areWebInstantAppsDisabled,
- debug, pkgSettingFunction);
+ debug, resolveForStart, pkgSettingFunction);
if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
@@ -461,13 +466,14 @@
* @param userId user id of source user
* @param areWebInstantAppsDisabled true if web instant apps are disabled
* @param debug true if resolution logs needed to be printed
+ * @param resolveForStart true if intent is for resolution
* @param pkgSettingFunction function to find PackageStateInternal for given package
* @return list of resolve infos
*/
private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
Computer computer, Intent intent, long matchFlags, List<ResolveInfo> candidates,
List<CrossProfileDomainInfo> crossProfileCandidates, int userId,
- boolean areWebInstantAppsDisabled, boolean debug,
+ boolean areWebInstantAppsDisabled, boolean debug, boolean resolveForStart,
Function<String, PackageStateInternal> pkgSettingFunction) {
final ArrayList<ResolveInfo> result = new ArrayList<>();
final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
@@ -525,7 +531,7 @@
// calling cross profile strategy to filter corresponding results
result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
- DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE));
+ DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, resolveForStart));
includeBrowser = true;
} else {
Pair<List<ResolveInfo>, Integer> infosAndLevel = mDomainVerificationManager
@@ -539,7 +545,7 @@
// calling cross profile strategy to filter corresponding results
result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
- DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE));
+ DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, resolveForStart));
} else {
result.addAll(approvedInfos);
@@ -547,7 +553,7 @@
// calling cross profile strategy to filter corresponding results
result.addAll(filterCrossProfileCandidatesWithDomainPreferredActivities(computer,
intent, matchFlags, categorizeResolveInfoByTargetUser, userId,
- highestApproval));
+ highestApproval, resolveForStart));
}
}
@@ -612,11 +618,13 @@
* CrossProfileDomainInfos
* @param sourceUserId user id for intent
* @param highestApprovalLevel domain approval level
+ * @param resolveForStart true if intent is for resolution
* @return list of ResolveInfos
*/
private List<ResolveInfo> filterCrossProfileCandidatesWithDomainPreferredActivities(
Computer computer, Intent intent, long flags, SparseArray<List<CrossProfileDomainInfo>>
- categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel) {
+ categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel,
+ boolean resolveForStart) {
List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>();
@@ -629,7 +637,8 @@
// finding cross profile strategy based on source and target user
CrossProfileResolver crossProfileIntentResolver =
chooseCrossProfileResolver(computer, sourceUserId,
- categorizeResolveInfoByTargetUser.keyAt(index));
+ categorizeResolveInfoByTargetUser.keyAt(index), resolveForStart,
+ flags);
// if strategy is available call it and add its filtered results
if (crossProfileIntentResolver != null) {
crossProfileDomainInfos.addAll(crossProfileIntentResolver
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 38efc10..d4e3549 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -255,6 +255,12 @@
@Override
@Deprecated
+ public final void clearPersistentPreferredActivity(IntentFilter filter, int userId) {
+ mPreferredActivityHelper.clearPersistentPreferredActivity(filter, userId);
+ }
+
+ @Override
+ @Deprecated
public final void clearPackagePreferredActivities(String packageName) {
mPreferredActivityHelper.clearPackagePreferredActivities(snapshot(),
packageName);
diff --git a/services/core/java/com/android/server/pm/NoFilteringResolver.java b/services/core/java/com/android/server/pm/NoFilteringResolver.java
index 492f915..999706a 100644
--- a/services/core/java/com/android/server/pm/NoFilteringResolver.java
+++ b/services/core/java/com/android/server/pm/NoFilteringResolver.java
@@ -16,7 +16,10 @@
package com.android.server.pm;
+import android.Manifest;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.provider.DeviceConfig;
@@ -47,13 +50,19 @@
/**
* Returns true if intent redirection for clone profile feature flag is set
- * @return value of flag allow_intent_redirection_for_clone_profile
+ * and if its query, then check if calling user have necessary permission
+ * (android.permission.QUERY_CLONED_APPS) as well as required flag
+ * (PackageManager.MATCH_CLONE_PROFILE) bit set.
+ * @return true if resolver would be used for cross profile resolution.
*/
- public static boolean isIntentRedirectionAllowed() {
+ public static boolean isIntentRedirectionAllowed(Context context,
+ boolean resolveForStart, long flags) {
final long token = Binder.clearCallingIdentity();
try {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
- FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, false /* defaultValue */);
+ FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, false /* defaultValue */)
+ && (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0)
+ && hasPermission(context, Manifest.permission.QUERY_CLONED_APPS)));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -123,4 +132,15 @@
// no filtering
return crossProfileDomainInfos;
}
+
+ /**
+ * Checks if calling uid have the mentioned permission
+ * @param context calling context
+ * @param permission permission name
+ * @return true if uid have the permission
+ */
+ private static boolean hasPermission(Context context, String permission) {
+ return context.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 93a119c..7f7a234 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -291,8 +291,8 @@
rollbackTimeoutIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
sessionId);
- rollbackTimeoutIntent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ rollbackTimeoutIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_FOREGROUND);
mPm.mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 12841a4..0685435 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2875,6 +2875,8 @@
newUserType = UserManager.USER_TYPE_FULL_DEMO;
} else if ("--ephemeral".equals(opt)) {
flags |= UserInfo.FLAG_EPHEMERAL;
+ } else if ("--for-testing".equals(opt)) {
+ flags |= UserInfo.FLAG_FOR_TESTING;
} else if ("--pre-create-only".equals(opt)) {
preCreateOnly = true;
} else if ("--user-type".equals(opt)) {
@@ -4269,8 +4271,8 @@
pw.println(" list users");
pw.println(" Lists the current users.");
pw.println("");
- pw.println(" create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral]");
- pw.println(" [--guest] [--pre-create-only] [--user-type USER_TYPE] USER_NAME");
+ pw.println(" create-user [--profileOf USER_ID] [--managed] [--restricted] [--guest]");
+ pw.println(" [--user-type USER_TYPE] [--ephemeral] [--for-testing] [--pre-create-only] USER_NAME");
pw.println(" Create a new user with the given USER_NAME, printing the new user identifier");
pw.println(" of the user.");
// TODO(b/142482943): Consider fetching the list of user types from UMS.
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 6f8995c..214a8b8 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -431,6 +431,23 @@
}
}
+ public void clearPersistentPreferredActivity(IntentFilter filter, int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "clearPersistentPreferredActivity can only be run by the system");
+ }
+ boolean changed = false;
+ synchronized (mPm.mLock) {
+ changed = mPm.mSettings.clearPersistentPreferredActivity(filter, userId);
+ }
+ if (changed) {
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
+ mPm.postPreferredActivityChangedBroadcast(userId);
+ mPm.scheduleWritePackageRestrictions(userId);
+ }
+ }
+
private boolean isHomeFilter(@NonNull WatchedIntentFilter filter) {
return filter.hasAction(Intent.ACTION_MAIN) && filter.hasCategory(Intent.CATEGORY_HOME)
&& filter.hasCategory(CATEGORY_DEFAULT);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index aedf782..165e476 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -99,6 +99,7 @@
import com.android.modules.utils.TypedXmlSerializer;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.permission.persistence.RuntimePermissionsState;
+import com.android.server.IntentResolver;
import com.android.server.LocalServices;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
@@ -2693,10 +2694,15 @@
FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
-1, -1);
- try {
- FileUtils.copy(mSettingsFilename, mSettingsReserveCopyFilename);
+ try (FileInputStream in = new FileInputStream(mSettingsFilename);
+ FileOutputStream out = new FileOutputStream(mSettingsReserveCopyFilename)) {
+ FileUtils.copy(in, out);
+ out.flush();
+ FileUtils.sync(out);
} catch (IOException e) {
- Slog.e(TAG, "Failed to backup settings", e);
+ Slog.e(TAG,
+ "Failed to write reserve copy of settings: " + mSettingsReserveCopyFilename,
+ e);
}
try {
@@ -6278,6 +6284,24 @@
return changed;
}
+ boolean clearPersistentPreferredActivity(IntentFilter filter, int userId) {
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
+ boolean changed = false;
+ while (it.hasNext()) {
+ PersistentPreferredActivity ppa = it.next();
+ if (IntentResolver.filterEquals(ppa.getIntentFilter(), filter)) {
+ ppir.removeFilter(ppa);
+ changed = true;
+ break;
+ }
+ }
+ if (changed) {
+ onChanged();
+ }
+ return changed;
+ }
+
ArrayList<Integer> systemReady(ComponentResolver resolver) {
// Verify that all of the preferred activity components actually
// exist. It is possible for applications to be updated and at
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 7b15e76..1787116 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -513,4 +513,20 @@
* @see UserManager#isMainUser()
*/
public abstract @UserIdInt int getMainUserId();
+
+ /**
+ * Returns the id of the user which should be in the foreground after boot completes.
+ *
+ * <p>If a boot user has been provided by calling {@link UserManager#setBootUser}, the
+ * returned value will be whatever was specified, as long as that user exists and can be
+ * switched to.
+ *
+ * <p>Otherwise, in {@link UserManager#isHeadlessSystemUserMode() headless system user mode},
+ * this will be the user who was last in the foreground on this device. If there is no
+ * switchable user on the device, a new user will be created and its id will be returned.
+ *
+ * <p>In non-headless system user mode, the return value will be {@link UserHandle#USER_SYSTEM}.
+ */
+ public abstract @UserIdInt int getBootUser()
+ throws UserManager.CheckedUserOperationException;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a8cf8cb..53a5648 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -21,6 +21,7 @@
import static android.os.UserManager.DEV_CREATE_OVERRIDE_PROPERTY;
import static android.os.UserManager.DISALLOW_USER_SWITCH;
import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
+import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
import android.Manifest;
import android.accounts.Account;
@@ -31,7 +32,6 @@
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
@@ -44,6 +44,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -100,6 +101,7 @@
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -127,11 +129,8 @@
import com.android.server.LockGuard;
import com.android.server.SystemService;
import com.android.server.am.UserState;
-import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
-import com.android.server.pm.UserManagerInternal.UserStartMode;
-import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -254,7 +253,8 @@
| UserInfo.FLAG_RESTRICTED
| UserInfo.FLAG_GUEST
| UserInfo.FLAG_DEMO
- | UserInfo.FLAG_FULL;
+ | UserInfo.FLAG_FULL
+ | UserInfo.FLAG_FOR_TESTING;
@VisibleForTesting
static final int MIN_USER_ID = UserHandle.MIN_SECONDARY_USER_ID;
@@ -637,6 +637,9 @@
private final UserVisibilityMediator mUserVisibilityMediator;
+ @GuardedBy("mUsersLock")
+ private @UserIdInt int mBootUser = UserHandle.USER_NULL;
+
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
@@ -936,6 +939,26 @@
}
@Override
+ public void setBootUser(@UserIdInt int userId) {
+ checkCreateUsersPermission("Set boot user");
+ synchronized (mUsersLock) {
+ // TODO(b/263381643): Change to EventLog.
+ Slogf.i(LOG_TAG, "setBootUser %d", userId);
+ mBootUser = userId;
+ }
+ }
+
+ @Override
+ public @UserIdInt int getBootUser() {
+ checkCreateUsersPermission("Get boot user");
+ try {
+ return mLocalService.getBootUser();
+ } catch (UserManager.CheckedUserOperationException e) {
+ throw e.toServiceSpecificException();
+ }
+ }
+
+ @Override
public int getPreviousFullUserToEnterForeground() {
checkQueryOrCreateUsersPermission("get previous user");
int previousUser = UserHandle.USER_NULL;
@@ -1569,6 +1592,8 @@
Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
}
name = getOwnerName();
+ } else if (orig.isMain()) {
+ name = getOwnerName();
} else if (orig.isGuest()) {
name = getGuestName();
}
@@ -1811,6 +1836,27 @@
}
/**
+ * Gets the current and target user ids as a {@link Pair}, calling
+ * {@link ActivityManagerInternal} directly (and without performing any permission check).
+ *
+ * @return ids of current foreground user and the target user. Target user will be
+ * {@link UserHandle#USER_NULL} if there is not an ongoing user switch. And if
+ * {@link ActivityManagerInternal} is not available yet, they will both be
+ * {@link UserHandle#USER_NULL}.
+ */
+ @VisibleForTesting
+ @NonNull
+ Pair<Integer, Integer> getCurrentAndTargetUserIds() {
+ ActivityManagerInternal activityManagerInternal = getActivityManagerInternal();
+ if (activityManagerInternal == null) {
+ Slog.w(LOG_TAG, "getCurrentAndTargetUserId() called too early, "
+ + "ActivityManagerInternal is not set yet");
+ return new Pair<>(UserHandle.USER_NULL, UserHandle.USER_NULL);
+ }
+ return activityManagerInternal.getCurrentAndTargetUserIds();
+ }
+
+ /**
* Gets the current user id, calling {@link ActivityManagerInternal} directly (and without
* performing any permission check).
*
@@ -4535,7 +4581,7 @@
UserHandle.USER_NULL, null);
if (userInfo == null) {
- throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN);
+ throw new ServiceSpecificException(USER_OPERATION_ERROR_UNKNOWN);
}
} catch (UserManager.CheckedUserOperationException e) {
throw e.toServiceSpecificException();
@@ -4664,7 +4710,7 @@
if (parent == null) {
throwCheckedUserOperationException(
"Cannot find user data for parent user " + parentId,
- UserManager.USER_OPERATION_ERROR_UNKNOWN);
+ USER_OPERATION_ERROR_UNKNOWN);
}
}
if (!preCreate && !canAddMoreUsersOfType(userTypeDetails)) {
@@ -4692,7 +4738,7 @@
&& !isCreationOverrideEnabled()) {
throwCheckedUserOperationException(
"Cannot add restricted profile - parent user must be system",
- UserManager.USER_OPERATION_ERROR_UNKNOWN);
+ USER_OPERATION_ERROR_UNKNOWN);
}
userId = getNextAvailableId();
@@ -5198,7 +5244,10 @@
data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.MULTI_USER_INFO,
UserManager.getMaxSupportedUsers(),
- isUserSwitcherEnabled(deviceOwnerUserId)));
+ isUserSwitcherEnabled(deviceOwnerUserId),
+ UserManager.supportsMultipleUsers()
+ && !hasUserRestriction(UserManager.DISALLOW_ADD_USER,
+ deviceOwnerUserId)));
}
} else {
Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag);
@@ -5402,11 +5451,15 @@
final long ident = Binder.clearCallingIdentity();
try {
final UserData userData;
- int currentUser = getCurrentUserId();
- if (currentUser == userId) {
+ Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
+ if (userId == currentAndTargetUserIds.first) {
Slog.w(LOG_TAG, "Current user cannot be removed.");
return false;
}
+ if (userId == currentAndTargetUserIds.second) {
+ Slog.w(LOG_TAG, "Target user of an ongoing user switch cannot be removed.");
+ return false;
+ }
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
userData = mUsers.get(userId);
@@ -5543,9 +5596,10 @@
}
}
- // Attempt to immediately remove a non-current user
- final int currentUser = getCurrentUserId();
- if (currentUser != userId) {
+ // Attempt to immediately remove a non-current and non-target user
+ Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
+ if (userId != currentAndTargetUserIds.first
+ && userId != currentAndTargetUserIds.second) {
// Attempt to remove the user. This will fail if the user is the current user
if (removeUserWithProfilesUnchecked(userId)) {
return UserManager.REMOVE_RESULT_REMOVED;
@@ -5554,9 +5608,14 @@
// If the user was not immediately removed, make sure it is marked as ephemeral.
// Don't mark as disabled since, per UserInfo.FLAG_DISABLED documentation, an
// ephemeral user should only be marked as disabled when its removal is in progress.
- Slog.i(LOG_TAG, "Unable to immediately remove user " + userId + " (current user is "
- + currentUser + "). User is set as ephemeral and will be removed on user "
- + "switch or reboot.");
+ Slog.i(LOG_TAG, TextUtils.formatSimple("Unable to immediately remove user %d "
+ + "(%s is %d). User is set as ephemeral and will be removed on "
+ + "user switch or reboot.",
+ userId,
+ userId == currentAndTargetUserIds.first
+ ? "current user"
+ : "target user of an ongoing user switch",
+ userId));
userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
writeUserLP(userData);
@@ -5598,29 +5657,24 @@
// Also, add the UserHandle for mainline modules which can't use the @hide
// EXTRA_USER_HANDLE.
removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
- mContext.sendOrderedBroadcastAsUser(removedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS,
-
- new BroadcastReceiver() {
+ getActivityManagerInternal().broadcastIntentWithCallback(removedIntent,
+ new IIntentReceiver.Stub() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
if (DBG) {
Slog.i(LOG_TAG,
"USER_REMOVED broadcast sent, cleaning up user data "
- + userId);
+ + userId);
}
- new Thread() {
- @Override
- public void run() {
- LocalServices.getService(ActivityManagerInternal.class)
- .onUserRemoved(userId);
- removeUserState(userId);
- }
- }.start();
+ new Thread(() -> {
+ getActivityManagerInternal().onUserRemoved(userId);
+ removeUserState(userId);
+ }).start();
}
},
-
- null, Activity.RESULT_OK, null, null);
+ new String[] {android.Manifest.permission.MANAGE_USERS},
+ UserHandle.USER_ALL, null, null, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6459,6 +6513,9 @@
if (DBG_ALLOCATION) {
pw.println(" System user allocations: " + mUser0Allocations.get());
}
+ synchronized (mUsersLock) {
+ pw.println(" Boot user: " + mBootUser);
+ }
pw.println();
pw.println("Number of listeners for");
@@ -6651,6 +6708,18 @@
return mLocalService.isUserInitialized(userId);
}
+ /**
+ * Creates a new user, intended to be the initial user on a device in headless system user mode.
+ */
+ private UserInfo createInitialUserForHsum() throws UserManager.CheckedUserOperationException {
+ final int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN;
+
+ // Null name will be replaced with "Owner" on-demand to allow for localisation.
+ return createUserInternalUnchecked(/* name= */ null, UserManager.USER_TYPE_FULL_SECONDARY,
+ flags, UserHandle.USER_NULL, /* preCreate= */ false,
+ /* disallowedPackages= */ null, /* token= */ null);
+ }
+
private class LocalService extends UserManagerInternal {
@Override
public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId,
@@ -7094,6 +7163,56 @@
return getMainUserIdUnchecked();
}
+ @Override
+ public @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException {
+ synchronized (mUsersLock) {
+ // TODO(b/242195409): On Automotive, block if boot user not provided.
+ if (mBootUser != UserHandle.USER_NULL) {
+ final UserData userData = mUsers.get(mBootUser);
+ if (userData != null && userData.info.supportsSwitchToByUser()) {
+ Slogf.i(LOG_TAG, "Using provided boot user: %d", mBootUser);
+ return mBootUser;
+ } else {
+ Slogf.w(LOG_TAG,
+ "Provided boot user cannot be switched to: %d", mBootUser);
+ }
+ }
+ }
+
+ if (isHeadlessSystemUserMode()) {
+ // Return the previous foreground user, if there is one.
+ final int previousUser = getPreviousFullUserToEnterForeground();
+ if (previousUser != UserHandle.USER_NULL) {
+ Slogf.i(LOG_TAG, "Boot user is previous user %d", previousUser);
+ return previousUser;
+ }
+ // No previous user. Return the first switchable user if there is one.
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ final UserData userData = mUsers.valueAt(i);
+ if (userData.info.supportsSwitchToByUser()) {
+ int firstSwitchable = userData.info.id;
+ Slogf.i(LOG_TAG,
+ "Boot user is first switchable user %d", firstSwitchable);
+ return firstSwitchable;
+ }
+ }
+ }
+ // No switchable users. Create the initial user.
+ final UserInfo newInitialUser = createInitialUserForHsum();
+ if (newInitialUser == null) {
+ throw new UserManager.CheckedUserOperationException(
+ "Initial user creation failed", USER_OPERATION_ERROR_UNKNOWN);
+ }
+ Slogf.i(LOG_TAG,
+ "No switchable users. Boot user is new user %d", newInitialUser.id);
+ return newInitialUser.id;
+ }
+ // Not HSUM, return system user.
+ return UserHandle.USER_SYSTEM;
+ }
+
} // class LocalService
@@ -7113,7 +7232,7 @@
+ restriction + " is enabled.";
Slog.w(LOG_TAG, errorMessage);
throw new UserManager.CheckedUserOperationException(errorMessage,
- UserManager.USER_OPERATION_ERROR_UNKNOWN);
+ USER_OPERATION_ERROR_UNKNOWN);
}
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 214fd61..3f2083f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -145,6 +145,7 @@
UserManager.DISALLOW_CAMERA_TOGGLE,
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserManager.DISALLOW_WIFI_TETHERING,
+ UserManager.DISALLOW_GRANT_ADMIN,
UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
UserManager.DISALLOW_WIFI_DIRECT,
UserManager.DISALLOW_ADD_WIFI_CONFIG,
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index a54f526..8ec6241 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -233,7 +233,8 @@
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
mSessionId);
enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
- enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_RECEIVER_FOREGROUND);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index 3fcb08a..2fbf3fb 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -900,6 +900,7 @@
break;
case EnergyConsumerType.MOBILE_RADIO:
buckets[EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO] = true;
+ buckets[EnergyConsumerStats.POWER_BUCKET_PHONE] = true;
break;
case EnergyConsumerType.DISPLAY:
buckets[EnergyConsumerStats.POWER_BUCKET_SCREEN_ON] = true;
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index f9482dd..2fb5cec 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -178,7 +178,7 @@
// TODO: remove "tcp" from network methods, since we measure total stats.
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- public static final int VERSION = 211;
+ public static final int VERSION = 212;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -5740,6 +5740,9 @@
HistoryItem.STATE2_PHONE_IN_CALL_FLAG);
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);
+ if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) {
+ scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO);
+ }
}
}
@@ -5750,6 +5753,7 @@
HistoryItem.STATE2_PHONE_IN_CALL_FLAG);
mPhoneOn = false;
mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);
+ scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO);
}
}
@@ -7425,6 +7429,12 @@
@GuardedBy("this")
@Override
+ public long getPhoneEnergyConsumptionUC() {
+ return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_PHONE);
+ }
+
+ @GuardedBy("this")
+ @Override
public long getScreenOnEnergyConsumptionUC() {
return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_SCREEN_ON);
}
@@ -12051,17 +12061,36 @@
}
synchronized (this) {
+ final long totalRadioDurationMs =
+ mMobileRadioActiveTimer.getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
+ final long phoneOnDurationMs = Math.min(totalRadioDurationMs,
+ mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000);
+ mPhoneOnTimer.setMark(elapsedRealtimeMs);
+
if (!mOnBatteryInternal || mIgnoreNextExternalStats) {
return;
}
final SparseDoubleArray uidEstimatedConsumptionMah;
+ final long dataConsumedChargeUC;
if (consumedChargeUC > 0 && isMobileRadioEnergyConsumerSupportedLocked()) {
+ // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the
+ // numerator for long rounding.
+ final long phoneConsumedChargeUC =
+ (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2)
+ / totalRadioDurationMs;
+ dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC;
+
mGlobalEnergyConsumerStats.updateStandardBucket(
- EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
+ EnergyConsumerStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC);
+ mGlobalEnergyConsumerStats.updateStandardBucket(
+ EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC);
uidEstimatedConsumptionMah = new SparseDoubleArray();
} else {
uidEstimatedConsumptionMah = null;
+ dataConsumedChargeUC = POWER_DATA_UNAVAILABLE;
}
RxTxConsumption rxTxConsumption = null;
@@ -12250,13 +12279,9 @@
totalEstimatedConsumptionMah += rxTxConsumption.txConsumptionMah;
} else {
// Estimate total active radio power consumption since last mark.
- final long totalRadioTimeMs =
- mMobileRadioActiveTimer.getTimeSinceMarkLocked(
- elapsedRealtimeMs * 1000) / 1000;
- mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
- totalRadioTimeMs);
+ totalRadioDurationMs);
// Estimate idle power consumption at each signal strength level
final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
@@ -12279,7 +12304,7 @@
mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
}
distributeEnergyToUidsLocked(EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO,
- consumedChargeUC, uidEstimatedConsumptionMah,
+ dataConsumedChargeUC, uidEstimatedConsumptionMah,
totalEstimatedConsumptionMah, elapsedRealtimeMs);
}
}
@@ -15041,6 +15066,8 @@
"record_usage_history";
public static final String KEY_PER_UID_MODEM_POWER_MODEL =
"per_uid_modem_power_model";
+ public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
+ "phone_on_external_stats_collection";
public static final String PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME =
"mobile_radio_active_time";
@@ -15089,6 +15116,7 @@
@PerUidModemPowerModel
private static final int DEFAULT_PER_UID_MODEM_MODEL =
PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
+ private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
/* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -15106,6 +15134,8 @@
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
public boolean RECORD_USAGE_HISTORY = DEFAULT_RECORD_USAGE_HISTORY;
public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
+ public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
+ DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -15187,6 +15217,10 @@
"");
PER_UID_MODEM_MODEL = getPerUidModemModel(perUidModemModel);
+ PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean(
+ KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION,
+ DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION);
+
updateBatteryChargedDelayMsLocked();
onChange();
@@ -15256,6 +15290,8 @@
pw.println(RECORD_USAGE_HISTORY);
pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
+ pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
+ pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION);
}
}
diff --git a/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java b/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
index bb89333..79ec6e2 100644
--- a/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
+++ b/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
@@ -42,14 +42,27 @@
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC();
+ final int powerModel = getPowerModel(energyConsumerUC, query);
+
final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED) / 1000;
- final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
- if (phoneOnPower != 0) {
- builder.getAggregateBatteryConsumerBuilder(
- BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
- .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+
+ final double phoneOnPower;
+ switch (powerModel) {
+ case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION:
+ phoneOnPower = uCtoMah(energyConsumerUC);
+ break;
+ case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+ default:
+ phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
}
+
+ if (phoneOnPower == 0.0) return;
+
+ builder.getAggregateBatteryConsumerBuilder(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel)
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 0fd6d9b..05b3ce7 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -217,4 +217,12 @@
* @see com.android.internal.statusbar.IStatusBar#enterStageSplitFromRunningApp
*/
void enterStageSplitFromRunningApp(boolean leftOrTop);
+
+ /**
+ * Shows the media output switcher dialog.
+ *
+ * @param packageName of the session for which the output switcher is shown.
+ * @see com.android.internal.statusbar.IStatusBar#showMediaOutputSwitcher
+ */
+ void showMediaOutputSwitcher(String packageName);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 97ca8df..0f49981 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -744,6 +744,16 @@
} catch (RemoteException ex) { }
}
}
+
+ @Override
+ public void showMediaOutputSwitcher(String packageName) {
+ if (mBar != null) {
+ try {
+ mBar.showMediaOutputSwitcher(packageName);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
};
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index fb9a4d4..301e612 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -79,6 +79,8 @@
*/
private Set<Integer> mShareFeClientIds = new HashSet<>();
+ private Set<Integer> mUsingDemuxHandles = new HashSet<>();
+
/**
* List of the Lnb handles that are used by the current client.
*/
@@ -233,6 +235,31 @@
}
/**
+ * Set when the client starts to use a Demux.
+ *
+ * @param demuxHandle the demux being used.
+ */
+ public void useDemux(int demuxHandle) {
+ mUsingDemuxHandles.add(demuxHandle);
+ }
+
+ /**
+ * Get the set of demux handles in use.
+ */
+ public Set<Integer> getInUseDemuxHandles() {
+ return mUsingDemuxHandles;
+ }
+
+ /**
+ * Called when the client released a Demux.
+ *
+ * @param demuxHandle the demux handl being released.
+ */
+ public void releaseDemux(int demuxHandle) {
+ mUsingDemuxHandles.remove(demuxHandle);
+ }
+
+ /**
* Set when the client starts to use an Lnb.
*
* @param lnbHandle being used.
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
new file mode 100644
index 0000000..df73565
--- /dev/null
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/DemuxResource.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.tv.tunerresourcemanager;
+
+/**
+ * A demux resource object used by the Tuner Resource Manager to record the tuner Demux
+ * information.
+ *
+ * @hide
+ */
+public final class DemuxResource extends TunerResourceBasic {
+
+ private final int mFilterTypes;
+
+ private DemuxResource(Builder builder) {
+ super(builder);
+ this.mFilterTypes = builder.mFilterTypes;
+ }
+
+ public int getFilterTypes() {
+ return mFilterTypes;
+ }
+
+ @Override
+ public String toString() {
+ return "DemuxResource[handle=" + this.mHandle + ", filterTypes="
+ + this.mFilterTypes + ", isInUse=" + this.mIsInUse
+ + ", ownerClientId=" + this.mOwnerClientId + "]";
+ }
+
+ /**
+ * Returns true if the desired {@link DemuxFilterMainTypes} is supported.
+ */
+ public boolean hasSufficientCaps(int desiredCaps) {
+ return desiredCaps == (desiredCaps & mFilterTypes);
+ }
+
+ /**
+ * Returns the number of supported {@link DemuxFilterMainTypes}.
+ */
+ public int getNumOfCaps() {
+ int mask = 1;
+ int numOfCaps = 0;
+ for (int i = 0; i < Integer.SIZE; i++) {
+ if ((mFilterTypes & mask) == mask) {
+ numOfCaps = numOfCaps + 1;
+ }
+ mask = mask << 1;
+ }
+ return numOfCaps;
+ }
+
+ /**
+ * Builder class for {@link DemuxResource}.
+ */
+ public static class Builder extends TunerResourceBasic.Builder {
+ private int mFilterTypes;
+
+ Builder(int handle) {
+ super(handle);
+ }
+
+ /**
+ * Builder for {@link DemuxResource}.
+ *
+ * @param filterTypes the supported {@link DemuxFilterMainTypes}
+ */
+ public Builder filterTypes(int filterTypes) {
+ this.mFilterTypes = filterTypes;
+ return this;
+ }
+
+ /**
+ * Build a {@link DemuxResource}.
+ *
+ * @return {@link DemuxResource}.
+ */
+ @Override
+ public DemuxResource build() {
+ DemuxResource demux = new DemuxResource(this);
+ return demux;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index ad1ff72..ed91775 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -22,6 +22,7 @@
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.tv.tuner.DemuxFilterMainType;
import android.media.IResourceManagerService;
import android.media.tv.TvInputManager;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -29,6 +30,7 @@
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
+import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
@@ -96,6 +98,8 @@
private SparseIntArray mFrontendUsedNumsBackup = new SparseIntArray();
private SparseIntArray mFrontendExistingNumsBackup = new SparseIntArray();
+ // Map of the current available demux resources
+ private Map<Integer, DemuxResource> mDemuxResources = new HashMap<>();
// Map of the current available lnb resources
private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
// Map of the current available Cas resources
@@ -249,6 +253,17 @@
}
@Override
+ public void setDemuxInfoList(@NonNull TunerDemuxInfo[] infos) throws RemoteException {
+ enforceTrmAccessPermission("setDemuxInfoList");
+ if (infos == null) {
+ throw new RemoteException("TunerDemuxInfo can't be null");
+ }
+ synchronized (mLock) {
+ setDemuxInfoListInternal(infos);
+ }
+ }
+
+ @Override
public void updateCasInfo(int casSystemId, int maxSessionNum) {
enforceTrmAccessPermission("updateCasInfo");
synchronized (mLock) {
@@ -294,8 +309,8 @@
@Override
public boolean setMaxNumberOfFrontends(int frontendType, int maxUsableNum) {
- enforceTunerAccessPermission("requestFrontend");
- enforceTrmAccessPermission("requestFrontend");
+ enforceTunerAccessPermission("setMaxNumberOfFrontends");
+ enforceTrmAccessPermission("setMaxNumberOfFrontends");
if (maxUsableNum < 0) {
Slog.w(TAG, "setMaxNumberOfFrontends failed with maxUsableNum:" + maxUsableNum
+ " frontendType:" + frontendType);
@@ -308,8 +323,8 @@
@Override
public int getMaxNumberOfFrontends(int frontendType) {
- enforceTunerAccessPermission("requestFrontend");
- enforceTrmAccessPermission("requestFrontend");
+ enforceTunerAccessPermission("getMaxNumberOfFrontends");
+ enforceTrmAccessPermission("getMaxNumberOfFrontends");
synchronized (mLock) {
return getMaxNumberOfFrontendsInternal(frontendType);
}
@@ -466,11 +481,33 @@
}
@Override
- public void releaseDemux(int demuxHandle, int clientId) {
+ public void releaseDemux(int demuxHandle, int clientId) throws RemoteException {
enforceTunerAccessPermission("releaseDemux");
enforceTrmAccessPermission("releaseDemux");
if (DEBUG) {
- Slog.d(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
+ Slog.e(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
+ }
+
+ synchronized (mLock) {
+ // For Tuner 2.0 and below or any HW constraint devices that are unable to support
+ // ITuner.openDemuxById(), demux resources are not really managed under TRM and
+ // mDemuxResources.size() will be zero
+ if (mDemuxResources.size() == 0) {
+ return;
+ }
+
+ if (!checkClientExists(clientId)) {
+ throw new RemoteException("Release demux for unregistered client:" + clientId);
+ }
+ DemuxResource demux = getDemuxResource(demuxHandle);
+ if (demux == null) {
+ throw new RemoteException("Releasing demux does not exist.");
+ }
+ if (demux.getOwnerClientId() != clientId) {
+ throw new RemoteException("Client is not the current owner "
+ + "of the releasing demux.");
+ }
+ releaseDemuxInternal(demux);
}
}
@@ -629,6 +666,7 @@
dumpSIA(mFrontendExistingNumsBackup, "FrontendExistingNumsBackup:", ", ", pw);
dumpSIA(mFrontendUsedNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
dumpSIA(mFrontendMaxUsableNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
+ dumpMap(mDemuxResources, "DemuxResource:", "\n", pw);
dumpMap(mLnbResources, "LnbResource:", "\n", pw);
dumpMap(mCasResources, "CasResource:", "\n", pw);
dumpMap(mCiCamResources, "CiCamResource:", "\n", pw);
@@ -859,6 +897,41 @@
}
@VisibleForTesting
+ protected void setDemuxInfoListInternal(TunerDemuxInfo[] infos) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateDemuxInfo:");
+ for (int i = 0; i < infos.length; i++) {
+ Slog.d(TAG, infos[i].toString());
+ }
+ }
+
+ // A set to record the demuxes pending on updating. Ids will be removed
+ // from this set once its updating finished. Any demux left in this set when all
+ // the updates are done will be removed from mDemuxResources.
+ Set<Integer> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
+
+ // Update demuxResources map and other mappings accordingly
+ for (int i = 0; i < infos.length; i++) {
+ if (getDemuxResource(infos[i].handle) != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Demux handle=" + infos[i].handle + "exists.");
+ }
+ updatingDemuxHandles.remove(infos[i].handle);
+ } else {
+ // Add a new demux resource
+ DemuxResource newDemux = new DemuxResource.Builder(infos[i].handle)
+ .filterTypes(infos[i].filterTypes)
+ .build();
+ addDemuxResource(newDemux);
+ }
+ }
+
+ for (int removingHandle : updatingDemuxHandles) {
+ // update the exclusive group id member list
+ removeDemuxResource(removingHandle);
+ }
+ }
+ @VisibleForTesting
protected void setLnbInfoListInternal(int[] lnbHandles) {
if (DEBUG) {
for (int i = 0; i < lnbHandles.length; i++) {
@@ -1292,6 +1365,14 @@
}
@VisibleForTesting
+ protected void releaseDemuxInternal(DemuxResource demux) {
+ if (DEBUG) {
+ Slog.d(TAG, "releaseDemux(DemuxHandle=" + demux.getHandle() + ")");
+ }
+ updateDemuxClientMappingOnRelease(demux);
+ }
+
+ @VisibleForTesting
protected void releaseLnbInternal(LnbResource lnb) {
if (DEBUG) {
Slog.d(TAG, "releaseLnb(lnbHandle=" + lnb.getHandle() + ")");
@@ -1320,9 +1401,91 @@
if (DEBUG) {
Slog.d(TAG, "requestDemux(request=" + request + ")");
}
- // There are enough Demux resources, so we don't manage Demux in R.
- demuxHandle[0] = generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
- return true;
+
+ // For Tuner 2.0 and below or any HW constraint devices that are unable to support
+ // ITuner.openDemuxById(), demux resources are not really managed under TRM and
+ // mDemuxResources.size() will be zero
+ if (mDemuxResources.size() == 0) {
+ // There are enough Demux resources, so we don't manage Demux in R.
+ demuxHandle[0] =
+ generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
+ return true;
+ }
+
+ demuxHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ ClientProfile requestClient = getClientProfile(request.clientId);
+
+ if (requestClient == null) {
+ return false;
+ }
+
+ clientPriorityUpdateOnRequest(requestClient);
+ int grantingDemuxHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ int inUseLowestPriorityDrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ // If the desired demux id was specified, we only need to check the demux.
+ boolean hasDesiredDemuxCap = request.desiredFilterTypes
+ != DemuxFilterMainType.UNDEFINED;
+ int smallestNumOfSupportedCaps = Integer.SIZE + 1;
+ for (DemuxResource dr : getDemuxResources().values()) {
+ if (!hasDesiredDemuxCap || dr.hasSufficientCaps(request.desiredFilterTypes)) {
+ if (!dr.isInUse()) {
+ int numOfSupportedCaps = dr.getNumOfCaps();
+
+ // look for the demux with minimum caps supporting the desired caps
+ if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
+ smallestNumOfSupportedCaps = numOfSupportedCaps;
+ grantingDemuxHandle = dr.getHandle();
+ }
+ } else if (grantingDemuxHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ // Record the demux id with the lowest client priority among all the
+ // in use demuxes when no availabledemux has been found.
+ int priority = updateAndGetOwnerClientPriority(dr.getOwnerClientId());
+ if (currentLowestPriority >= priority) {
+ int numOfSupportedCaps = dr.getNumOfCaps();
+ boolean shouldUpdate = false;
+ // update lowest priority
+ if (currentLowestPriority > priority) {
+ currentLowestPriority = priority;
+ shouldUpdate = true;
+ }
+ // update smallest caps
+ if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
+ smallestNumOfSupportedCaps = numOfSupportedCaps;
+ shouldUpdate = true;
+ }
+ if (shouldUpdate) {
+ inUseLowestPriorityDrHandle = dr.getHandle();
+ }
+ }
+ }
+ }
+ }
+
+ // Grant demux when there is unused resource.
+ if (grantingDemuxHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ demuxHandle[0] = grantingDemuxHandle;
+ updateDemuxClientMappingOnNewGrant(grantingDemuxHandle, request.clientId);
+ return true;
+ }
+
+ // When all the resources are occupied, grant the lowest priority resource if the
+ // request client has higher priority.
+ if (inUseLowestPriorityDrHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE
+ && (requestClient.getPriority() > currentLowestPriority)) {
+ if (!reclaimResource(
+ getDemuxResource(inUseLowestPriorityDrHandle).getOwnerClientId(),
+ TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX)) {
+ return false;
+ }
+ demuxHandle[0] = inUseLowestPriorityDrHandle;
+ updateDemuxClientMappingOnNewGrant(
+ inUseLowestPriorityDrHandle, request.clientId);
+ return true;
+ }
+
+ return false;
}
@VisibleForTesting
@@ -1673,6 +1836,21 @@
ownerProfile.setPrimaryFrontend(grantingHandle);
}
+ private void updateDemuxClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
+ DemuxResource grantingDemux = getDemuxResource(grantingHandle);
+ if (grantingDemux != null) {
+ ClientProfile ownerProfile = getClientProfile(ownerClientId);
+ grantingDemux.setOwner(ownerClientId);
+ ownerProfile.useDemux(grantingHandle);
+ }
+ }
+
+ private void updateDemuxClientMappingOnRelease(@NonNull DemuxResource releasingDemux) {
+ ClientProfile ownerProfile = getClientProfile(releasingDemux.getOwnerClientId());
+ releasingDemux.removeOwner();
+ ownerProfile.releaseDemux(releasingDemux.getHandle());
+ }
+
private void updateLnbClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
LnbResource grantingLnb = getLnbResource(grantingHandle);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -1764,6 +1942,17 @@
return mFrontendResources;
}
+ @VisibleForTesting
+ @Nullable
+ protected DemuxResource getDemuxResource(int demuxHandle) {
+ return mDemuxResources.get(demuxHandle);
+ }
+
+ @VisibleForTesting
+ protected Map<Integer, DemuxResource> getDemuxResources() {
+ return mDemuxResources;
+ }
+
private boolean setMaxNumberOfFrontendsInternal(int frontendType, int maxUsableNum) {
int usedNum = mFrontendUsedNums.get(frontendType, INVALID_FE_COUNT);
if (usedNum == INVALID_FE_COUNT || usedNum <= maxUsableNum) {
@@ -1887,6 +2076,10 @@
}
+ private void addDemuxResource(DemuxResource newDemux) {
+ mDemuxResources.put(newDemux.getHandle(), newDemux);
+ }
+
private void removeFrontendResource(int removingHandle) {
FrontendResource fe = getFrontendResource(removingHandle);
if (fe == null) {
@@ -1907,6 +2100,17 @@
mFrontendResources.remove(removingHandle);
}
+ private void removeDemuxResource(int removingHandle) {
+ DemuxResource demux = getDemuxResource(removingHandle);
+ if (demux == null) {
+ return;
+ }
+ if (demux.isInUse()) {
+ releaseDemuxInternal(demux);
+ }
+ mDemuxResources.remove(removingHandle);
+ }
+
@VisibleForTesting
@Nullable
protected LnbResource getLnbResource(int lnbHandle) {
@@ -2062,6 +2266,10 @@
if (profile.getInUseCiCamId() != ClientProfile.INVALID_RESOURCE_ID) {
getCiCamResource(profile.getInUseCiCamId()).removeOwner(profile.getId());
}
+ // Clear Demux
+ for (Integer demuxHandle : profile.getInUseDemuxHandles()) {
+ getDemuxResource(demuxHandle).removeOwner();
+ }
// Clear Frontend
clearFrontendAndClientMapping(profile);
profile.reclaimAllResources();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
new file mode 100644
index 0000000..a380dea
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
@@ -0,0 +1,137 @@
+/*
+ * 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 android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Binder;
+import android.os.Debug;
+import android.util.Slog;
+import android.util.SparseArray;
+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;
+/**
+ * Internal class used to store all the display data relevant to the wallpapers
+ */
+class WallpaperDisplayHelper {
+
+ @VisibleForTesting
+ static final class DisplayData {
+ int mWidth = -1;
+ int mHeight = -1;
+ final Rect mPadding = new Rect(0, 0, 0, 0);
+ final int mDisplayId;
+ DisplayData(int displayId) {
+ mDisplayId = displayId;
+ }
+ }
+
+ private static final String TAG = WallpaperDisplayHelper.class.getSimpleName();
+ private final SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();
+ private final DisplayManager mDisplayManager;
+ private final WindowManagerInternal mWindowManagerInternal;
+
+ WallpaperDisplayHelper(
+ DisplayManager displayManager,
+ WindowManagerInternal windowManagerInternal) {
+ mDisplayManager = displayManager;
+ mWindowManagerInternal = windowManagerInternal;
+ }
+
+ DisplayData getDisplayDataOrCreate(int displayId) {
+ DisplayData wpdData = mDisplayDatas.get(displayId);
+ if (wpdData == null) {
+ wpdData = new DisplayData(displayId);
+ ensureSaneWallpaperDisplaySize(wpdData, displayId);
+ mDisplayDatas.append(displayId, wpdData);
+ }
+ return wpdData;
+ }
+
+ void removeDisplayData(int displayId) {
+ mDisplayDatas.remove(displayId);
+ }
+
+ void ensureSaneWallpaperDisplaySize(DisplayData wpdData, int displayId) {
+ // We always want to have some reasonable width hint.
+ final int baseSize = getMaximumSizeDimension(displayId);
+ if (wpdData.mWidth < baseSize) {
+ wpdData.mWidth = baseSize;
+ }
+ if (wpdData.mHeight < baseSize) {
+ wpdData.mHeight = baseSize;
+ }
+ }
+
+ int getMaximumSizeDimension(int displayId) {
+ Display display = mDisplayManager.getDisplay(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Invalid displayId=" + displayId + " " + Debug.getCallers(4));
+ display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ }
+ return display.getMaximumSizeDimension();
+ }
+
+ void forEachDisplayData(Consumer<DisplayData> action) {
+ for (int i = mDisplayDatas.size() - 1; i >= 0; i--) {
+ final DisplayData wpdData = mDisplayDatas.valueAt(i);
+ action.accept(wpdData);
+ }
+ }
+
+ Display[] getDisplays() {
+ return mDisplayManager.getDisplays();
+ }
+
+ DisplayInfo getDisplayInfo(int displayId) {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ mDisplayManager.getDisplay(displayId).getDisplayInfo(displayInfo);
+ return displayInfo;
+ }
+
+ boolean isUsableDisplay(int displayId, int clientUid) {
+ return isUsableDisplay(mDisplayManager.getDisplay(displayId), clientUid);
+ }
+
+ boolean isUsableDisplay(Display display, int clientUid) {
+ if (display == null || !display.hasAccess(clientUid)) {
+ return false;
+ }
+ final int displayId = display.getDisplayId();
+ if (displayId == DEFAULT_DISPLAY) {
+ return true;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ boolean isValidDisplay(int displayId) {
+ return mDisplayManager.getDisplay(displayId) != null;
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6edfebf..075bac1 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -32,6 +32,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wallpaper.WallpaperDisplayHelper.DisplayData;
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;
@@ -79,7 +80,6 @@
import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Bundle;
-import android.os.Debug;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
@@ -609,10 +609,9 @@
boolean success = false;
// Only generate crop for default display.
- final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
final Rect cropHint = new Rect(wallpaper.cropHint);
- final DisplayInfo displayInfo = new DisplayInfo();
- mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo);
+ final DisplayInfo displayInfo = mWallpaperDisplayHelper.getDisplayInfo(DEFAULT_DISPLAY);
if (DEBUG) {
Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
@@ -829,7 +828,8 @@
private final MyPackageMonitor mMonitor;
private final AppOpsManager mAppOpsManager;
- private final DisplayManager mDisplayManager;
+ // TODO("b/264637309") probably move this in WallpaperDisplayUtils,
+ // after logic is changed for the lockscreen lwp project
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@@ -848,12 +848,12 @@
targetWallpaper = mFallbackWallpaper;
}
if (targetWallpaper == null) return;
- WallpaperConnection.DisplayConnector connector =
+ DisplayConnector connector =
targetWallpaper.connection.getDisplayConnectorOrCreate(displayId);
if (connector == null) return;
connector.disconnectLocked();
targetWallpaper.connection.removeDisplayConnector(displayId);
- removeDisplayData(displayId);
+ mWallpaperDisplayHelper.removeDisplayData(displayId);
}
for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) {
final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks =
@@ -904,8 +904,6 @@
private final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
private final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
- private SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();
-
protected WallpaperData mFallbackWallpaper;
private final SparseBooleanArray mUserRestorecon = new SparseBooleanArray();
@@ -914,57 +912,7 @@
private LocalColorRepository mLocalColorRepo = new LocalColorRepository();
@VisibleForTesting
- static final class DisplayData {
- int mWidth = -1;
- int mHeight = -1;
- final Rect mPadding = new Rect(0, 0, 0, 0);
- final int mDisplayId;
-
- DisplayData(int displayId) {
- mDisplayId = displayId;
- }
- }
-
- private void removeDisplayData(int displayId) {
- mDisplayDatas.remove(displayId);
- }
-
- private DisplayData getDisplayDataOrCreate(int displayId) {
- DisplayData wpdData = mDisplayDatas.get(displayId);
- if (wpdData == null) {
- wpdData = new DisplayData(displayId);
- ensureSaneWallpaperDisplaySize(wpdData, displayId);
- mDisplayDatas.append(displayId, wpdData);
- }
- return wpdData;
- }
-
- private void ensureSaneWallpaperDisplaySize(DisplayData wpdData, int displayId) {
- // We always want to have some reasonable width hint.
- final int baseSize = getMaximumSizeDimension(displayId);
- if (wpdData.mWidth < baseSize) {
- wpdData.mWidth = baseSize;
- }
- if (wpdData.mHeight < baseSize) {
- wpdData.mHeight = baseSize;
- }
- }
-
- private int getMaximumSizeDimension(int displayId) {
- Display display = mDisplayManager.getDisplay(displayId);
- if (display == null) {
- Slog.w(TAG, "Invalid displayId=" + displayId + " " + Debug.getCallers(4));
- display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- }
- return display.getMaximumSizeDimension();
- }
-
- void forEachDisplayData(Consumer<DisplayData> action) {
- for (int i = mDisplayDatas.size() - 1; i >= 0; i--) {
- final DisplayData wpdData = mDisplayDatas.valueAt(i);
- action.accept(wpdData);
- }
- }
+ final WallpaperDisplayHelper mWallpaperDisplayHelper;
private boolean supportsMultiDisplay(WallpaperConnection connection) {
if (connection != null) {
@@ -993,7 +941,7 @@
}
} else {
fallbackConnection.appendConnectorWithCondition(display ->
- fallbackConnection.isUsableDisplay(display)
+ mWallpaperDisplayHelper.isUsableDisplay(display, fallbackConnection.mClientUid)
&& display.getDisplayId() != DEFAULT_DISPLAY
&& !fallbackConnection.containsDisplay(display.getDisplayId()));
fallbackConnection.forEachDisplayConnector(connector -> {
@@ -1004,84 +952,87 @@
}
}
- class WallpaperConnection extends IWallpaperConnection.Stub
- implements ServiceConnection {
+ /**
+ * Collect needed info for a display.
+ */
+ @VisibleForTesting
+ final class DisplayConnector {
+ final int mDisplayId;
+ final Binder mToken = new Binder();
+ IWallpaperEngine mEngine;
+ boolean mDimensionsChanged;
+ boolean mPaddingChanged;
- /**
- * Collect needed info for a display.
- */
- @VisibleForTesting
- final class DisplayConnector {
- final int mDisplayId;
- final Binder mToken = new Binder();
- IWallpaperEngine mEngine;
- boolean mDimensionsChanged;
- boolean mPaddingChanged;
+ DisplayConnector(int displayId) {
+ mDisplayId = displayId;
+ }
- DisplayConnector(int displayId) {
- mDisplayId = displayId;
- }
-
- void ensureStatusHandled() {
- final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
- if (mDimensionsChanged) {
- try {
- mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to set wallpaper dimensions", e);
- }
- mDimensionsChanged = false;
- }
- if (mPaddingChanged) {
- try {
- mEngine.setDisplayPadding(wpdData.mPadding);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to set wallpaper padding", e);
- }
- mPaddingChanged = false;
- }
- }
-
- void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
- if (connection.mService == null) {
- Slog.w(TAG, "WallpaperService is not connected yet");
- return;
- }
- TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
- t.traceBegin("WPMS.connectLocked-" + wallpaper.wallpaperComponent);
- if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
- mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
- null /* options */);
- final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
+ void ensureStatusHandled() {
+ final DisplayData wpdData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId);
+ if (mDimensionsChanged) {
try {
- connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
- wpdData.mWidth, wpdData.mHeight,
- wpdData.mPadding, mDisplayId, mWallpaper.mWhich);
+ mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed attaching wallpaper on display", e);
- if (wallpaper != null && !wallpaper.wallpaperUpdating
- && connection.getConnectedEngineSize() == 0) {
- bindWallpaperComponentLocked(null /* componentName */, false /* force */,
- false /* fromUser */, wallpaper, null /* reply */);
- }
+ Slog.w(TAG, "Failed to set wallpaper dimensions", e);
}
- t.traceEnd();
+ mDimensionsChanged = false;
}
-
- void disconnectLocked() {
- if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
- mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
- mDisplayId);
+ if (mPaddingChanged) {
try {
- if (mEngine != null) {
- mEngine.destroy();
- }
+ mEngine.setDisplayPadding(wpdData.mPadding);
} catch (RemoteException e) {
+ Slog.w(TAG, "Failed to set wallpaper padding", e);
}
- mEngine = null;
+ mPaddingChanged = false;
}
}
+ void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
+ if (connection.mService == null) {
+ Slog.w(TAG, "WallpaperService is not connected yet");
+ return;
+ }
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+ t.traceBegin("WPMS.connectLocked-" + wallpaper.wallpaperComponent);
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
+ mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
+ null /* options */);
+ final DisplayData wpdData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId);
+ try {
+ connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
+ wpdData.mWidth, wpdData.mHeight,
+ wpdData.mPadding, mDisplayId, wallpaper.mWhich);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed attaching wallpaper on display", e);
+ if (wallpaper != null && !wallpaper.wallpaperUpdating
+ && connection.getConnectedEngineSize() == 0) {
+ bindWallpaperComponentLocked(null /* componentName */, false /* force */,
+ false /* fromUser */, wallpaper, null /* reply */);
+ }
+ }
+ t.traceEnd();
+ }
+
+ void disconnectLocked() {
+ if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
+ mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
+ mDisplayId);
+ try {
+ if (mEngine != null) {
+ mEngine.destroy();
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Engine.destroy() threw a RemoteException");
+ }
+ mEngine = null;
+ }
+ }
+
+ class WallpaperConnection extends IWallpaperConnection.Stub
+ implements ServiceConnection {
+
/**
* A map for each display.
* Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable.
@@ -1132,7 +1083,8 @@
if (!mWallpaper.equals(mFallbackWallpaper)) {
if (supportsMultiDisplay(this)) {
// The system wallpaper is image wallpaper or it can supports multiple displays.
- appendConnectorWithCondition(this::isUsableDisplay);
+ appendConnectorWithCondition(display ->
+ mWallpaperDisplayHelper.isUsableDisplay(display, mClientUid));
} else {
// The system wallpaper does not support multiple displays, so just attach it on
// default display.
@@ -1143,37 +1095,18 @@
}
private void appendConnectorWithCondition(Predicate<Display> tester) {
- final Display[] displays = mDisplayManager.getDisplays();
+ final Display[] displays = mWallpaperDisplayHelper.getDisplays();
for (Display display : displays) {
if (tester.test(display)) {
final int displayId = display.getDisplayId();
final DisplayConnector connector = mDisplayConnector.get(displayId);
if (connector == null) {
- mDisplayConnector.append(displayId,
- new DisplayConnector(displayId));
+ mDisplayConnector.append(displayId, new DisplayConnector(displayId));
}
}
}
}
- @VisibleForTesting
- boolean isUsableDisplay(Display display) {
- if (display == null || !display.hasAccess(mClientUid)) {
- return false;
- }
- final int displayId = display.getDisplayId();
- if (displayId == DEFAULT_DISPLAY) {
- return true;
- }
-
- final long ident = Binder.clearCallingIdentity();
- try {
- return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
void forEachDisplayConnector(Consumer<DisplayConnector> action) {
for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
final DisplayConnector connector = mDisplayConnector.valueAt(i);
@@ -1193,8 +1126,7 @@
DisplayConnector getDisplayConnectorOrCreate(int displayId) {
DisplayConnector connector = mDisplayConnector.get(displayId);
if (connector == null) {
- final Display display = mDisplayManager.getDisplay(displayId);
- if (isUsableDisplay(display)) {
+ if (mWallpaperDisplayHelper.isUsableDisplay(displayId, mClientUid)) {
connector = new DisplayConnector(displayId);
mDisplayConnector.append(displayId, connector);
}
@@ -1633,8 +1565,9 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mIPackageManager = AppGlobals.getPackageManager();
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
+ DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+ dm.registerDisplayListener(mDisplayListener, null /* handler */);
+ mWallpaperDisplayHelper = new WallpaperDisplayHelper(dm, mWindowManagerInternal);
mActivityManager = mContext.getSystemService(ActivityManager.class);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
@@ -2084,10 +2017,6 @@
return false;
}
- private boolean isValidDisplay(int displayId) {
- return mDisplayManager.getDisplay(displayId) != null;
- }
-
/**
* Sets the dimension hint for the wallpaper. These hints indicate the desired
* minimum width and height for the wallpaper in a particular display.
@@ -2110,18 +2039,18 @@
throw new IllegalArgumentException("width and height must be > 0");
}
- if (!isValidDisplay(displayId)) {
+ if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) {
throw new IllegalArgumentException("Cannot find display with id=" + displayId);
}
- final DisplayData wpdData = getDisplayDataOrCreate(displayId);
+ final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId);
if (width != wpdData.mWidth || height != wpdData.mHeight) {
wpdData.mWidth = width;
wpdData.mHeight = height;
if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- final WallpaperConnection.DisplayConnector connector = wallpaper.connection
+ final DisplayConnector connector = wallpaper.connection
.getDisplayConnectorOrCreate(displayId);
final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
if (engine != null) {
@@ -2146,12 +2075,13 @@
*/
public int getWidthHint(int displayId) throws RemoteException {
synchronized (mLock) {
- if (!isValidDisplay(displayId)) {
+ if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) {
throw new IllegalArgumentException("Cannot find display with id=" + displayId);
}
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
if (wallpaper != null) {
- final DisplayData wpdData = getDisplayDataOrCreate(displayId);
+ final DisplayData wpdData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId);
return wpdData.mWidth;
} else {
return 0;
@@ -2164,12 +2094,13 @@
*/
public int getHeightHint(int displayId) throws RemoteException {
synchronized (mLock) {
- if (!isValidDisplay(displayId)) {
+ if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) {
throw new IllegalArgumentException("Cannot find display with id=" + displayId);
}
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
if (wallpaper != null) {
- final DisplayData wpdData = getDisplayDataOrCreate(displayId);
+ final DisplayData wpdData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId);
return wpdData.mHeight;
} else {
return 0;
@@ -2186,7 +2117,7 @@
return;
}
synchronized (mLock) {
- if (!isValidDisplay(displayId)) {
+ if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) {
throw new IllegalArgumentException("Cannot find display with id=" + displayId);
}
int userId = UserHandle.getCallingUserId();
@@ -2195,7 +2126,7 @@
throw new IllegalArgumentException("padding must be positive: " + padding);
}
- int maxSize = getMaximumSizeDimension(displayId);
+ int maxSize = mWallpaperDisplayHelper.getMaximumSizeDimension(displayId);
final int paddingWidth = padding.left + padding.right;
final int paddingHeight = padding.top + padding.bottom;
@@ -2208,13 +2139,13 @@
+ " exceeds max height " + maxSize);
}
- final DisplayData wpdData = getDisplayDataOrCreate(displayId);
+ final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId);
if (!padding.equals(wpdData.mPadding)) {
wpdData.mPadding.set(padding);
if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- final WallpaperConnection.DisplayConnector connector = wallpaper.connection
+ final DisplayConnector connector = wallpaper.connection
.getDisplayConnectorOrCreate(displayId);
final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
if (engine != null) {
@@ -2268,7 +2199,8 @@
return null;
}
// Only for default display.
- final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final DisplayData wpdData =
+ mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
try {
if (outParams != null) {
outParams.putInt("width", wpdData.mWidth);
@@ -3155,8 +3087,7 @@
Slog.w(TAG, "Failed detaching wallpaper service ", e);
}
mContext.unbindService(wallpaper.connection);
- wallpaper.connection.forEachDisplayConnector(
- WallpaperConnection.DisplayConnector::disconnectLocked);
+ wallpaper.connection.forEachDisplayConnector(DisplayConnector::disconnectLocked);
wallpaper.connection.mService = null;
wallpaper.connection.mDisplayConnector.clear();
@@ -3286,7 +3217,7 @@
return;
}
if (supportsMultiDisplay(mLastWallpaper.connection)) {
- final WallpaperConnection.DisplayConnector connector =
+ final DisplayConnector connector =
mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId);
if (connector == null) return;
connector.connectLocked(mLastWallpaper.connection, mLastWallpaper);
@@ -3295,7 +3226,7 @@
// System wallpaper does not support multiple displays, attach this display to
// the fallback wallpaper.
if (mFallbackWallpaper != null) {
- final WallpaperConnection.DisplayConnector connector = mFallbackWallpaper
+ final DisplayConnector connector = mFallbackWallpaper
.connection.getDisplayConnectorOrCreate(displayId);
if (connector == null) return;
connector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper);
@@ -3352,7 +3283,7 @@
if (DEBUG) {
Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
}
- final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
out.startTag(null, tag);
out.attributeInt(null, "id", wallpaper.wallpaperId);
out.attributeInt(null, "width", wpdData.mWidth);
@@ -3536,7 +3467,7 @@
initializeFallbackWallpaper();
}
boolean success = false;
- final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
try {
stream = new FileInputStream(file);
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
@@ -3613,7 +3544,7 @@
}
}
- ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY);
+ mWallpaperDisplayHelper.ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY);
ensureSaneWallpaperData(wallpaper);
WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
if (lockWallpaper != null) {
@@ -3653,7 +3584,7 @@
wallpaper.wallpaperId = makeWallpaperIdLocked();
}
- final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
+ final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY);
if (!keepDimensionHints) {
wpData.mWidth = parser.getAttributeInt(null, "width");
@@ -3866,7 +3797,7 @@
pw.print(" User "); pw.print(wallpaper.userId);
pw.print(": id="); pw.println(wallpaper.wallpaperId);
pw.println(" Display state:");
- forEachDisplayData(wpSize -> {
+ mWallpaperDisplayHelper.forEachDisplayData(wpSize -> {
pw.print(" displayId=");
pw.println(wpSize.mDisplayId);
pw.print(" mWidth=");
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 43d3111..a7883cb 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -33,6 +33,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -277,7 +278,7 @@
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
reason);
@@ -298,7 +299,7 @@
.setUserId(userId)
.setInTask(inTask)
.setOriginatingPendingIntent(originatingPendingIntent)
- .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
+ .setBackgroundStartPrivileges(backgroundStartPrivileges)
.execute();
}
@@ -317,10 +318,11 @@
final int startActivitiesInPackage(int uid, String callingPackage,
@Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes,
IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
+ PendingIntentRecord originatingPendingIntent,
+ BackgroundStartPrivileges backgroundStartPrivileges) {
return startActivitiesInPackage(uid, 0 /* realCallingPid */, -1 /* realCallingUid */,
callingPackage, callingFeatureId, intents, resolvedTypes, resultTo, options, userId,
- validateIncomingUser, originatingPendingIntent, allowBackgroundActivityStart);
+ validateIncomingUser, originatingPendingIntent, backgroundStartPrivileges);
}
/**
@@ -340,7 +342,7 @@
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
final String reason = "startActivityInPackage";
@@ -350,14 +352,14 @@
// TODO: Switch to user app stacks here.
return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage,
callingFeatureId, intents, resolvedTypes, resultTo, options, userId, reason,
- originatingPendingIntent, allowBackgroundActivityStart);
+ originatingPendingIntent, backgroundStartPrivileges);
}
int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid,
int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
int userId, String reason, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
@@ -465,7 +467,7 @@
// top one as otherwise an activity below might consume it.
.setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
.setOriginatingPendingIntent(originatingPendingIntent)
- .setAllowBackgroundActivityStart(allowBackgroundActivityStart);
+ .setBackgroundStartPrivileges(backgroundStartPrivileges);
}
// Log if the activities to be started have different uids.
if (startingUidPkgs.size() > 1) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 40432dc..d88f719 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -95,6 +95,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
@@ -389,7 +390,8 @@
WaitResult waitResult;
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
- boolean allowBackgroundActivityStart;
+ BackgroundStartPrivileges backgroundStartPrivileges;
+
/**
* The error callback token passed in {@link android.window.WindowContainerTransaction}
* for TaskFragment operation error handling via
@@ -449,7 +451,7 @@
allowPendingRemoteAnimationRegistryLookup = true;
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
- allowBackgroundActivityStart = false;
+ backgroundStartPrivileges = BackgroundStartPrivileges.NONE;
errorCallbackToken = null;
}
@@ -492,7 +494,7 @@
= request.allowPendingRemoteAnimationRegistryLookup;
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
- allowBackgroundActivityStart = request.allowBackgroundActivityStart;
+ backgroundStartPrivileges = request.backgroundStartPrivileges;
errorCallbackToken = request.errorCallbackToken;
}
@@ -1060,7 +1062,7 @@
realCallingPid,
callerApp,
request.originatingPendingIntent,
- request.allowBackgroundActivityStart,
+ request.backgroundStartPrivileges,
intent,
checkedOptions);
} finally {
@@ -3182,8 +3184,9 @@
return this;
}
- ActivityStarter setAllowBackgroundActivityStart(boolean allowBackgroundActivityStart) {
- mRequest.allowBackgroundActivityStart = allowBackgroundActivityStart;
+ ActivityStarter setBackgroundStartPrivileges(
+ BackgroundStartPrivileges backgroundStartPrivileges) {
+ mRequest.backgroundStartPrivileges = backgroundStartPrivileges;
return this;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index c51808a..bd4f1a6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -21,6 +21,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppProtoEnums;
+import android.app.BackgroundStartPrivileges;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
@@ -209,14 +210,14 @@
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart);
+ BackgroundStartPrivileges backgroundStartPrivileges);
public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, @Nullable String callingFeaturId, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart);
+ BackgroundStartPrivileges backgroundStartPrivileges);
/**
* Callback to be called on certain activity start scenarios.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9a8ef19..070ad2d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -136,6 +136,7 @@
import android.app.AnrController;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.BackgroundStartPrivileges;
import android.app.Dialog;
import android.app.IActivityClientController;
import android.app.IActivityController;
@@ -1222,7 +1223,7 @@
return getActivityStartController().startActivities(caller, -1, 0, -1, callingPackage,
callingFeatureId, intents, resolvedTypes, resultTo,
SafeActivityOptions.fromBundle(bOptions), userId, reason,
- null /* originatingPendingIntent */, false /* allowBackgroundActivityStart */);
+ null /* originatingPendingIntent */, BackgroundStartPrivileges.NONE);
}
@Override
@@ -1527,7 +1528,7 @@
// To start the dream from background, we need to start it from a persistent
// system process. Here we set the real calling uid to the system server uid
.setRealCallingUid(Binder.getCallingUid())
- .setAllowBackgroundActivityStart(true)
+ .setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
return true;
} finally {
@@ -1677,7 +1678,7 @@
.setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
// The target may well be in the background, which would normally prevent it
// from starting an activity. Here we definitely want the start to succeed.
- .setAllowBackgroundActivityStart(true)
+ .setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
@@ -1723,7 +1724,7 @@
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
- .setAllowBackgroundActivityStart(true)
+ .setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
}
@@ -1750,7 +1751,7 @@
.setResolvedType(resolvedType)
.setActivityOptions(bOptions)
.setUserId(userId)
- .setAllowBackgroundActivityStart(true)
+ .setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2200,7 +2201,7 @@
-1,
callerApp,
null,
- false,
+ BackgroundStartPrivileges.NONE,
null,
null)) {
if (!isBackgroundActivityStartsEnabled()) {
@@ -5605,7 +5606,7 @@
intents, resolvedTypes, null /* resultTo */,
SafeActivityOptions.fromBundle(bOptions), userId,
false /* validateIncomingUser */, null /* originatingPendingIntent */,
- false /* allowBackgroundActivityStart */);
+ BackgroundStartPrivileges.NONE);
}
@Override
@@ -5613,12 +5614,12 @@
String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
assertPackageMatchesCallingUid(callingPackage);
return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intents, resolvedTypes,
resultTo, options, userId, validateIncomingUser, originatingPendingIntent,
- allowBackgroundActivityStart);
+ backgroundStartPrivileges);
}
@Override
@@ -5627,13 +5628,13 @@
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
assertPackageMatchesCallingUid(callingPackage);
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, options, userId, inTask,
reason, validateIncomingUser, originatingPendingIntent,
- allowBackgroundActivityStart);
+ backgroundStartPrivileges);
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 919bab8..8149e1c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -90,6 +90,7 @@
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
+import android.app.BackgroundStartPrivileges;
import android.app.IActivityClientController;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
@@ -2731,7 +2732,7 @@
callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
- false /* allowBackgroundActivityStart */);
+ BackgroundStartPrivileges.NONE);
} finally {
PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(false);
synchronized (mService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 7bd8c53..de38a20 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -20,6 +20,7 @@
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import android.app.ActivityManager;
+import android.app.BackgroundStartPrivileges;
import android.app.IAppTask;
import android.app.IApplicationThread;
import android.content.Intent;
@@ -131,7 +132,7 @@
-1,
callerApp,
null,
- false,
+ BackgroundStartPrivileges.NONE,
null,
null)) {
if (!mService.isBackgroundActivityStartsEnabled()) {
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 2315795..7aa734b 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -31,6 +31,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -135,12 +136,12 @@
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart,
+ BackgroundStartPrivileges backgroundStartPrivileges,
Intent intent,
ActivityOptions checkedOptions) {
return checkBackgroundActivityStart(callingUid, callingPid, callingPackage,
realCallingUid, realCallingPid, callerApp, originatingPendingIntent,
- allowBackgroundActivityStart, intent, checkedOptions) == BAL_BLOCK;
+ backgroundStartPrivileges, intent, checkedOptions) == BAL_BLOCK;
}
/**
@@ -156,7 +157,7 @@
int realCallingPid,
WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart,
+ BackgroundStartPrivileges backgroundStartPrivileges,
Intent intent,
ActivityOptions checkedOptions) {
// don't abort for the most important UIDs
@@ -254,10 +255,12 @@
}
// Legacy behavior allows to use caller foreground state to bypass BAL restriction.
- final boolean balAllowedByPiSender =
- PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
-
- if (balAllowedByPiSender && realCallingUid != callingUid) {
+ // The options here are the options passed by the sender and not those on the intent.
+ final BackgroundStartPrivileges balAllowedByPiSender =
+ PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
+ checkedOptions, realCallingUid);
+ if (balAllowedByPiSender.allowsBackgroundActivityStarts()
+ && realCallingUid != callingUid) {
final boolean useCallerPermission =
PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
if (useCallerPermission
@@ -282,7 +285,8 @@
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
- if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
+ if (isRealCallingUidPersistentSystemProcess
+ && backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
return logStartAllowedAndReturnCode(/*background*/ false,
callingUid,
BAL_ALLOW_PENDING_INTENT,
@@ -338,7 +342,7 @@
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
// caller if caller allows, so that we can make the decision based on its state.
int callerAppUid = callingUid;
- if (callerApp == null && balAllowedByPiSender) {
+ if (callerApp == null && balAllowedByPiSender.allowsBackgroundActivityStarts()) {
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
callerAppUid = realCallingUid;
}
@@ -399,8 +403,8 @@
+ isRealCallingUidPersistentSystemProcess
+ "; originatingPendingIntent: "
+ originatingPendingIntent
- + "; allowBackgroundActivityStart: "
- + allowBackgroundActivityStart
+ + "; backgroundStartPrivileges: "
+ + backgroundStartPrivileges
+ "; intent: "
+ intent
+ "; callerApp: "
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 020e9c58..bdb06a97 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -27,20 +28,31 @@
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.BackgroundStartPrivileges;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
+import android.content.Context;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.function.IntPredicate;
/**
@@ -52,6 +64,12 @@
private static final String TAG =
TAG_WITH_CLASS_NAME ? "BackgroundLaunchProcessController" : TAG_ATM;
+ /** If enabled BAL are prevented by default in applications targeting U and later. */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Overridable
+ private static final long DEFAULT_RESCIND_BAL_FG_PRIVILEGES_BOUND_SERVICE = 261072174;
+
/** It is {@link ActivityTaskManagerService#hasActiveVisibleWindow(int)}. */
private final IntPredicate mUidHasActiveVisibleWindowPredicate;
@@ -63,11 +81,13 @@
* (can be null) and are used to trace back the grant to the notification token mechanism.
*/
@GuardedBy("this")
- private @Nullable ArrayMap<Binder, IBinder> mBackgroundActivityStartTokens;
+ private @Nullable ArrayMap<Binder, BackgroundStartPrivileges> mBackgroundStartPrivileges;
- /** Set of UIDs of clients currently bound to this process. */
+ /** Set of UIDs of clients currently bound to this process and opt in to allow this process to
+ * launch background activity.
+ */
@GuardedBy("this")
- private @Nullable IntArray mBoundClientUids;
+ private @Nullable IntArray mBalOptInBoundClientUids;
BackgroundLaunchProcessController(@NonNull IntPredicate uidHasActiveVisibleWindowPredicate,
@Nullable BackgroundActivityStartCallback callback) {
@@ -153,30 +173,54 @@
private boolean isBackgroundStartAllowedByToken(int uid, String packageName,
boolean isCheckingForFgsStart) {
synchronized (this) {
- if (mBackgroundActivityStartTokens == null
- || mBackgroundActivityStartTokens.isEmpty()) {
+ if (mBackgroundStartPrivileges == null
+ || mBackgroundStartPrivileges.isEmpty()) {
+ // no tokens to allow anything
return false;
}
if (isCheckingForFgsStart) {
- // BG-FGS-start only checks if there is a token.
- return true;
+ // check if any token allows foreground service starts
+ for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) {
+ if (mBackgroundStartPrivileges.valueAt(i).allowsBackgroundFgsStarts()) {
+ return true;
+ }
+ }
+ return false;
}
-
if (mBackgroundActivityStartCallback == null) {
- // We have tokens but no callback to decide => allow.
- return true;
+ // without a callback just check if any token allows background activity starts
+ for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) {
+ if (mBackgroundStartPrivileges.valueAt(i)
+ .allowsBackgroundActivityStarts()) {
+ return true;
+ }
+ }
+ return false;
}
+ List<IBinder> binderTokens = getOriginatingTokensThatAllowBal();
// The callback will decide.
return mBackgroundActivityStartCallback.isActivityStartAllowed(
- mBackgroundActivityStartTokens.values(), uid, packageName);
+ binderTokens, uid, packageName);
}
}
+ private List<IBinder> getOriginatingTokensThatAllowBal() {
+ List<IBinder> originatingTokens = new ArrayList<>();
+ for (int i = mBackgroundStartPrivileges.size(); i-- > 0; ) {
+ BackgroundStartPrivileges privilege =
+ mBackgroundStartPrivileges.valueAt(i);
+ if (privilege.allowsBackgroundActivityStarts()) {
+ originatingTokens.add(privilege.getOriginatingToken());
+ }
+ }
+ return originatingTokens;
+ }
+
private boolean isBoundByForegroundUid() {
synchronized (this) {
- if (mBoundClientUids != null) {
- for (int i = mBoundClientUids.size() - 1; i >= 0; i--) {
- if (mUidHasActiveVisibleWindowPredicate.test(mBoundClientUids.get(i))) {
+ if (mBalOptInBoundClientUids != null) {
+ for (int i = mBalOptInBoundClientUids.size() - 1; i >= 0; i--) {
+ if (mUidHasActiveVisibleWindowPredicate.test(mBalOptInBoundClientUids.get(i))) {
return true;
}
}
@@ -185,48 +229,61 @@
return false;
}
- void setBoundClientUids(ArraySet<Integer> boundClientUids) {
+ void clearBalOptInBoundClientUids() {
synchronized (this) {
- if (boundClientUids == null || boundClientUids.isEmpty()) {
- mBoundClientUids = null;
- return;
- }
- if (mBoundClientUids == null) {
- mBoundClientUids = new IntArray();
+ if (mBalOptInBoundClientUids == null) {
+ mBalOptInBoundClientUids = new IntArray();
} else {
- mBoundClientUids.clear();
+ mBalOptInBoundClientUids.clear();
}
- for (int i = boundClientUids.size() - 1; i >= 0; i--) {
- mBoundClientUids.add(boundClientUids.valueAt(i));
+ }
+ }
+
+ void addBoundClientUid(int clientUid, String clientPackageName, int bindFlags) {
+ if (!CompatChanges.isChangeEnabled(
+ DEFAULT_RESCIND_BAL_FG_PRIVILEGES_BOUND_SERVICE,
+ clientPackageName,
+ UserHandle.getUserHandleForUid(clientUid))
+ || (bindFlags & Context.BIND_ALLOW_ACTIVITY_STARTS) != 0) {
+ if (mBalOptInBoundClientUids == null) {
+ mBalOptInBoundClientUids = new IntArray();
+ }
+ if (mBalOptInBoundClientUids.indexOf(clientUid) == -1) {
+ mBalOptInBoundClientUids.add(clientUid);
}
}
}
/**
* Allows background activity starts using token {@code entity}. Optionally, you can provide
- * {@code originatingToken} if you have one such originating token, this is useful for tracing
- * back the grant in the case of the notification token.
+ * {@code originatingToken} in the {@link BackgroundStartPrivileges} if you have one such
+ * originating token, this is useful for tracing back the grant in the case of the notification
+ * token.
*
* If {@code entity} is already added, this method will update its {@code originatingToken}.
*/
- void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
- @Nullable IBinder originatingToken) {
+ void addOrUpdateAllowBackgroundStartPrivileges(
+ Binder entity, BackgroundStartPrivileges backgroundStartPrivileges) {
+ requireNonNull(entity, "entity");
+ requireNonNull(backgroundStartPrivileges, "backgroundStartPrivileges");
+ checkArgument(backgroundStartPrivileges.allowsAny());
synchronized (this) {
- if (mBackgroundActivityStartTokens == null) {
- mBackgroundActivityStartTokens = new ArrayMap<>();
+ if (mBackgroundStartPrivileges == null) {
+ mBackgroundStartPrivileges = new ArrayMap<>();
}
- mBackgroundActivityStartTokens.put(entity, originatingToken);
+ mBackgroundStartPrivileges.put(entity, backgroundStartPrivileges);
}
}
/**
* Removes token {@code entity} that allowed background activity starts added via {@link
- * #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}.
+ * #addOrUpdateAllowBackgroundStartPrivileges(Binder, BackgroundStartPrivileges)}.
*/
- void removeAllowBackgroundActivityStartsToken(Binder entity) {
+ void removeAllowBackgroundStartPrivileges(Binder entity) {
+ requireNonNull(entity, "entity");
synchronized (this) {
- if (mBackgroundActivityStartTokens != null) {
- mBackgroundActivityStartTokens.remove(entity);
+ if (mBackgroundStartPrivileges != null) {
+ mBackgroundStartPrivileges.remove(entity);
}
}
}
@@ -240,33 +297,33 @@
return false;
}
synchronized (this) {
- if (mBackgroundActivityStartTokens == null
- || mBackgroundActivityStartTokens.isEmpty()) {
+ if (mBackgroundStartPrivileges == null
+ || mBackgroundStartPrivileges.isEmpty()) {
return false;
}
return mBackgroundActivityStartCallback.canCloseSystemDialogs(
- mBackgroundActivityStartTokens.values(), uid);
+ getOriginatingTokensThatAllowBal(), uid);
}
}
void dump(PrintWriter pw, String prefix) {
synchronized (this) {
- if (mBackgroundActivityStartTokens != null
- && !mBackgroundActivityStartTokens.isEmpty()) {
+ if (mBackgroundStartPrivileges != null
+ && !mBackgroundStartPrivileges.isEmpty()) {
pw.print(prefix);
pw.println("Background activity start tokens (token: originating token):");
- for (int i = mBackgroundActivityStartTokens.size() - 1; i >= 0; i--) {
+ for (int i = mBackgroundStartPrivileges.size() - 1; i >= 0; i--) {
pw.print(prefix);
pw.print(" - ");
- pw.print(mBackgroundActivityStartTokens.keyAt(i));
+ pw.print(mBackgroundStartPrivileges.keyAt(i));
pw.print(": ");
- pw.println(mBackgroundActivityStartTokens.valueAt(i));
+ pw.println(mBackgroundStartPrivileges.valueAt(i));
}
}
- if (mBoundClientUids != null && mBoundClientUids.size() > 0) {
+ if (mBalOptInBoundClientUids != null && mBalOptInBoundClientUids.size() > 0) {
pw.print(prefix);
pw.print("BoundClientUids:");
- pw.println(Arrays.toString(mBoundClientUids.toArray()));
+ pw.println(Arrays.toString(mBalOptInBoundClientUids.toArray()));
}
}
}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index af135b7..9e258cb 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -20,6 +20,7 @@
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
+import static android.view.ViewProtoEnums.DISPLAY_STATE_OFF;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
@@ -317,6 +318,11 @@
if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
mRecordedWindowContainer.asTask().isVisibleRequested());
+ } else {
+ int currentDisplayState =
+ mRecordedWindowContainer.asDisplayContent().getDisplay().getState();
+ mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
+ currentDisplayState != DISPLAY_STATE_OFF);
}
// No need to clean up. In SurfaceFlinger, parents hold references to their children. The
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eadb11e..63d6509 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3030,7 +3030,7 @@
if (density == getInitialDisplayDensity()) {
density = 0;
}
- mWmService.mDisplayWindowSettings.setForcedDensity(this, density, userId);
+ mWmService.mDisplayWindowSettings.setForcedDensity(getDisplayInfo(), density, userId);
}
/** @param mode {@link #FORCE_SCALING_MODE_AUTO} or {@link #FORCE_SCALING_MODE_DISABLED}. */
@@ -6841,12 +6841,12 @@
public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
try {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS);
mRemoteInsetsController.showInsets(types, fromIme, statsToken);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver showInsets", e);
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS);
}
}
@@ -6855,12 +6855,12 @@
public void hideInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
try {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS);
mRemoteInsetsController.hideInsets(types, fromIme, statsToken);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver hideInsets", e);
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 6d47eeb..4c0435e 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -77,14 +77,14 @@
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
- void setForcedDensity(DisplayContent displayContent, int density, int userId) {
- if (displayContent.isDefaultDisplay) {
+ void setForcedDensity(DisplayInfo info, int density, int userId) {
+ if (info.displayId == Display.DEFAULT_DISPLAY) {
final String densityString = density == 0 ? "" : Integer.toString(density);
Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
}
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = info;
final SettingsProvider.SettingsEntry overrideSettings =
mSettingsProvider.getOverrideSettings(displayInfo);
overrideSettings.mForcedDensity = density;
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 85938e3..60e2e95 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -182,7 +182,8 @@
boolean targetChanged = isTargetChangedWithinActivity(imeTarget);
mImeRequester = imeTarget;
// There was still a stats token, so that request presumably failed.
- ImeTracker.get().onFailed(mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
+ ImeTracker.forLogging().onFailed(
+ mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
mImeRequesterStatsToken = statsToken;
if (targetChanged) {
// target changed, check if new target can show IME.
@@ -197,12 +198,12 @@
ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeRequester.getWindow() == null
? mImeRequester : mImeRequester.getWindow().getName());
mShowImeRunner = () -> {
- ImeTracker.get().onProgress(mImeRequesterStatsToken,
+ ImeTracker.forLogging().onProgress(mImeRequesterStatsToken,
ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
// Target should still be the same.
if (isReadyToShowIme()) {
- ImeTracker.get().onProgress(mImeRequesterStatsToken,
+ ImeTracker.forLogging().onProgress(mImeRequesterStatsToken,
ImeTracker.PHASE_WM_SHOW_IME_READY);
final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL);
@@ -219,7 +220,7 @@
? mImeRequester.getWindow().getName() : ""));
}
} else {
- ImeTracker.get().onFailed(mImeRequesterStatsToken,
+ ImeTracker.forLogging().onFailed(mImeRequesterStatsToken,
ImeTracker.PHASE_WM_SHOW_IME_READY);
}
// Clear token here so we don't report an error in abortShowImePostLayout().
@@ -258,7 +259,8 @@
mImeRequester = null;
mIsImeLayoutDrawn = false;
mShowImeRunner = null;
- ImeTracker.get().onCancelled(mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
+ ImeTracker.forLogging().onCancelled(
+ mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
mImeRequesterStatsToken = null;
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 1df534f..874f942 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -707,7 +707,8 @@
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- false /* disable */, 0 /* floatingImeBottomInsets */, null);
+ false /* disable */, 0 /* floatingImeBottomInsets */,
+ null /* loggingListener */, null /* jankContext */);
mFinishCallback = finishCallback;
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e253ce0..b7021c8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -610,7 +610,7 @@
*/
ActivityRecord mChildPipActivity;
- boolean mLastSurfaceShowing = true;
+ boolean mLastSurfaceShowing;
boolean mAlignActivityLocaleWithTask = false;
@@ -4131,13 +4131,7 @@
@Override
boolean showSurfaceOnCreation() {
- if (mCreatedByOrganizer) {
- // Tasks created by the organizer are default visible because they can synchronously
- // update the leash before new children are added to the task.
- return true;
- }
- // Organized tasks handle their own surface visibility
- return !canBeOrganized();
+ return false;
}
@Override
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index e538584..cd23959 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -209,6 +209,7 @@
private boolean mIsSeamlessRotation = false;
private IContainerFreezer mContainerFreezer = null;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
@@ -362,6 +363,10 @@
return mState == STATE_COLLECTING || mState == STATE_STARTED;
}
+ boolean isStarted() {
+ return mState == STATE_STARTED;
+ }
+
@VisibleForTesting
void startCollecting(long timeoutMs) {
startCollecting(timeoutMs, TransitionController.SYNC_METHOD);
@@ -395,6 +400,12 @@
applyReady();
mController.mTransitionTracer.logState(this);
+
+ mController.updateAnimatingState(mTmpTransaction);
+ // merge into the next-time the global transaction is applied. This is too-early to set
+ // early-wake anyways, so we don't need to apply immediately (in fact applying right now
+ // can preempt more-important work).
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
/**
@@ -895,6 +906,8 @@
false /* forceRelayout */);
}
cleanUpInternal();
+ mController.updateAnimatingState(mTmpTransaction);
+ mTmpTransaction.apply();
}
void abort() {
@@ -1071,8 +1084,6 @@
"Calling onTransitionReady: %s", info);
mController.getTransitionPlayer().onTransitionReady(
mToken, info, transaction, mFinishTransaction);
- // Since we created root-leash but no longer reference it from core, release it now
- info.releaseAnimSurfaces();
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
System.identityHashCode(this));
@@ -1089,6 +1100,9 @@
mOverrideOptions = null;
reportStartReasonsToLogger();
+
+ // Since we created root-leash but no longer reference it from core, release it now
+ info.releaseAnimSurfaces();
}
/**
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 1758102..73cd251 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -35,6 +35,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -117,7 +118,7 @@
*/
boolean mBuildingFinishLayers = false;
- private final SurfaceControl.Transaction mWakeT = new SurfaceControl.Transaction();
+ private boolean mAnimatingState = false;
TransitionController(ActivityTaskManagerService atm,
TaskSnapshotController taskSnapshotController,
@@ -623,20 +624,30 @@
mTransitionTracer.logState(transition);
}
+ void updateAnimatingState(SurfaceControl.Transaction t) {
+ final boolean animatingState = !mPlayingTransitions.isEmpty()
+ || (mCollectingTransition != null && mCollectingTransition.isStarted());
+ if (animatingState && !mAnimatingState) {
+ t.setEarlyWakeupStart();
+ // Usually transitions put quite a load onto the system already (with all the things
+ // happening in app), so pause task snapshot persisting to not increase the load.
+ mAtm.mWindowManager.mSnapshotPersistQueue.setPaused(true);
+ mAnimatingState = true;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "transitAnim", 0);
+ } else if (!animatingState && mAnimatingState) {
+ t.setEarlyWakeupEnd();
+ mAtm.mWindowManager.mSnapshotPersistQueue.setPaused(false);
+ mAnimatingState = false;
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "transitAnim", 0);
+ }
+ }
+
/** Updates the process state of animation player. */
private void updateRunningRemoteAnimation(Transition transition, boolean isPlaying) {
if (mTransitionPlayerProc == null) return;
if (isPlaying) {
- mWakeT.setEarlyWakeupStart();
- mWakeT.apply();
- // Usually transitions put quite a load onto the system already (with all the things
- // happening in app), so pause task snapshot persisting to not increase the load.
- mAtm.mWindowManager.mSnapshotPersistQueue.setPaused(true);
mTransitionPlayerProc.setRunningRemoteAnimation(true);
} else if (mPlayingTransitions.isEmpty()) {
- mWakeT.setEarlyWakeupEnd();
- mWakeT.apply();
- mAtm.mWindowManager.mSnapshotPersistQueue.setPaused(false);
mTransitionPlayerProc.setRunningRemoteAnimation(false);
mRemotePlayer.clear();
return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0243a98..18ad43c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5855,6 +5855,11 @@
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
return displayContent.getInitialDisplayDensity();
}
+
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null && info.hasAccess(Binder.getCallingUid())) {
+ return info.logicalDensityDpi;
+ }
}
return -1;
}
@@ -5901,6 +5906,11 @@
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
displayContent.setForcedDensity(density, targetUserId);
+ } else {
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null) {
+ mDisplayWindowSettings.setForcedDensity(info, density, userId);
+ }
}
}
} finally {
@@ -5925,6 +5935,12 @@
if (displayContent != null) {
displayContent.setForcedDensity(displayContent.getInitialDisplayDensity(),
callingUserId);
+ } else {
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null) {
+ mDisplayWindowSettings.setForcedDensity(info, info.logicalDensityDpi,
+ userId);
+ }
}
}
} finally {
@@ -8071,14 +8087,14 @@
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
}
if (dc != null && dc.getImeTarget(IME_TARGET_CONTROL) != null) {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
ProtoLog.d(WM_DEBUG_IME, "hideIme Control target: %s ",
dc.getImeTarget(IME_TARGET_CONTROL));
dc.getImeTarget(IME_TARGET_CONTROL).hideInsets(WindowInsets.Type.ime(),
true /* fromIme */, statsToken);
} else {
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
}
if (dc != null) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 3e279b2..2980c76 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -50,6 +50,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
import android.app.servertransaction.ConfigurationChangeItem;
@@ -64,13 +65,11 @@
import android.os.Binder;
import android.os.Build;
import android.os.FactoryTest;
-import android.os.IBinder;
import android.os.LocaleList;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -547,17 +546,18 @@
}
/**
- * @see BackgroundLaunchProcessController#addOrUpdateAllowBackgroundActivityStartsToken(Binder,
- * IBinder)
+ * @see BackgroundLaunchProcessController#addOrUpdateAllowBackgroundStartPrivileges(Binder,
+ * BackgroundStartPrivileges)
*/
- public void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
- @Nullable IBinder originatingToken) {
- mBgLaunchController.addOrUpdateAllowBackgroundActivityStartsToken(entity, originatingToken);
+ public void addOrUpdateBackgroundStartPrivileges(Binder entity,
+ BackgroundStartPrivileges backgroundStartPrivileges) {
+ mBgLaunchController.addOrUpdateAllowBackgroundStartPrivileges(entity,
+ backgroundStartPrivileges);
}
- /** @see BackgroundLaunchProcessController#removeAllowBackgroundActivityStartsToken(Binder) */
- public void removeAllowBackgroundActivityStartsToken(Binder entity) {
- mBgLaunchController.removeAllowBackgroundActivityStartsToken(entity);
+ /** @see BackgroundLaunchProcessController#removeAllowBackgroundStartPrivileges(Binder) */
+ public void removeBackgroundStartPrivileges(Binder entity) {
+ mBgLaunchController.removeAllowBackgroundStartPrivileges(entity);
}
/**
@@ -593,8 +593,18 @@
return mBgLaunchController.canCloseSystemDialogsByToken(mUid);
}
- public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
- mBgLaunchController.setBoundClientUids(boundClientUids);
+ /**
+ * Clear all bound client Uids.
+ */
+ public void clearBoundClientUids() {
+ mBgLaunchController.clearBalOptInBoundClientUids();
+ }
+
+ /**
+ * Add bound client Uid.
+ */
+ public void addBoundClientUid(int clientUid, String clientPackageName, int bindFlags) {
+ mBgLaunchController.addBoundClientUid(clientUid, clientPackageName, bindFlags);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 828a89a..7a0070b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3993,12 +3993,12 @@
public void showInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
try {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS);
mClient.showInsets(types, fromIme, statsToken);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver showInsets", e);
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS);
}
}
@@ -4007,12 +4007,12 @@
public void hideInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
try {
- ImeTracker.get().onProgress(statsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS);
mClient.hideInsets(types, fromIme, statsToken);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver hideInsets", e);
- ImeTracker.get().onFailed(statsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java
new file mode 100644
index 0000000..d400000
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.devicepolicy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.util.Log;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+final class ComponentNamePolicySerializer extends PolicySerializer<ComponentName> {
+ private static final String ATTR_PACKAGE_NAME = ":package-name";
+ private static final String ATTR_CLASS_NAME = ":class-name";
+
+ @Override
+ void saveToXml(
+ TypedXmlSerializer serializer, String attributeNamePrefix, @NonNull ComponentName value)
+ throws IOException {
+ Objects.requireNonNull(value);
+ serializer.attribute(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_PACKAGE_NAME, value.getPackageName());
+ serializer.attribute(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_CLASS_NAME, value.getClassName());
+ }
+
+ @Nullable
+ @Override
+ ComponentName readFromXml(TypedXmlPullParser parser, String attributeNamePrefix) {
+ String packageName = parser.getAttributeValue(
+ /* namespace= */ null, attributeNamePrefix + ATTR_PACKAGE_NAME);
+ String className = parser.getAttributeValue(
+ /* namespace= */ null, attributeNamePrefix + ATTR_CLASS_NAME);
+ if (packageName == null || className == null) {
+ Log.e(DevicePolicyEngine.TAG, "Error parsing ComponentName policy.");
+ return null;
+ }
+ return new ComponentName(packageName, className);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DefaultPolicyKey.java b/services/devicepolicy/java/com/android/server/devicepolicy/DefaultPolicyKey.java
new file mode 100644
index 0000000..ab0fc99
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DefaultPolicyKey.java
@@ -0,0 +1,42 @@
+/*
+ * 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.devicepolicy;
+
+import com.android.modules.utils.TypedXmlPullParser;
+
+/**
+ * Default implementation for {@link PolicyKey} used to identify a policy that doesn't require any
+ * additional arguments to be represented in the policy engine's data structure.
+ */
+final class DefaultPolicyKey extends PolicyKey {
+ private static final String ATTR_GENERIC_POLICY_KEY = "generic-policy-key";
+
+ DefaultPolicyKey(String policyKey) {
+ super(policyKey);
+ }
+
+ String getKey() {
+ return mKey;
+ }
+
+ static DefaultPolicyKey readGenericPolicyKeyFromXml(TypedXmlPullParser parser) {
+ String genericPolicyKey = parser.getAttributeValue(
+ /* namespace= */ null, ATTR_GENERIC_POLICY_KEY);
+ return new DefaultPolicyKey(genericPolicyKey);
+ }
+
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 7ec809f..cb3b021 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -16,14 +16,10 @@
package com.android.server.devicepolicy;
-import static android.app.admin.PolicyUpdateReason.REASON_CONFLICTING_ADMIN_POLICY;
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_SET_RESULT_KEY;
+import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_CONFLICTING_ADMIN_POLICY;
+import static android.app.admin.PolicyUpdateResult.RESULT_SUCCESS;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_TARGET_USER_ID;
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_UPDATE_REASON_KEY;
-import static android.app.admin.PolicyUpdatesReceiver.POLICY_SET_RESULT_FAILURE;
-import static android.app.admin.PolicyUpdatesReceiver.POLICY_SET_RESULT_SUCCESS;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY;
import android.Manifest;
import android.annotation.NonNull;
@@ -82,12 +78,12 @@
/**
* Map of <userId, Map<policyKey, policyState>>
*/
- private final SparseArray<Map<String, PolicyState<?>>> mLocalPolicies;
+ private final SparseArray<Map<PolicyKey, PolicyState<?>>> mLocalPolicies;
/**
* Map of <policyKey, policyState>
*/
- private final Map<String, PolicyState<?>> mGlobalPolicies;
+ private final Map<PolicyKey, PolicyState<?>> mGlobalPolicies;
/**
* Map containing the current set of admins in each user with active policies.
@@ -146,9 +142,8 @@
sendPolicyResultToAdmin(
enforcingAdmin,
policyDefinition,
- policyEnforced,
// TODO: we're always sending this for now, should properly handle errors.
- REASON_CONFLICTING_ADMIN_POLICY,
+ policyEnforced ? RESULT_SUCCESS : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
userId);
updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
@@ -194,9 +189,8 @@
sendPolicyResultToAdmin(
enforcingAdmin,
policyDefinition,
- policyEnforced,
// TODO: we're always sending this for now, should properly handle errors.
- REASON_CONFLICTING_ADMIN_POLICY,
+ policyEnforced ? RESULT_SUCCESS : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
userId);
if (localPolicyState.getPoliciesSetByAdmins().isEmpty()) {
@@ -223,7 +217,7 @@
// Send policy updates to admins who've set it locally
sendPolicyChangedToAdmins(
- localPolicyState.getPoliciesSetByAdmins().keySet(),
+ localPolicyState,
enforcingAdmin,
policyDefinition,
// This policy change is only relevant to a single user, not the global
@@ -234,7 +228,7 @@
if (hasGlobalPolicyLocked(policyDefinition)) {
PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
sendPolicyChangedToAdmins(
- globalPolicyState.getPoliciesSetByAdmins().keySet(),
+ globalPolicyState,
enforcingAdmin,
policyDefinition,
userId);
@@ -266,13 +260,13 @@
policyDefinition, enforcingAdmin, value);
boolean policyEnforcedGlobally = Objects.equals(
globalPolicyState.getCurrentResolvedPolicy(), value);
+ boolean policyEnforced = policyEnforcedGlobally && policyEnforcedOnAllUsers;
sendPolicyResultToAdmin(
enforcingAdmin,
policyDefinition,
- policyEnforcedGlobally && policyEnforcedOnAllUsers,
// TODO: we're always sending this for now, should properly handle errors.
- REASON_CONFLICTING_ADMIN_POLICY,
+ policyEnforced ? RESULT_SUCCESS : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
UserHandle.USER_ALL);
updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
@@ -305,13 +299,13 @@
policyDefinition, enforcingAdmin, /* value= */ null);
// For a removePolicy to be enforced, it means no current policy exists
boolean policyEnforcedGlobally = policyState.getCurrentResolvedPolicy() == null;
+ boolean policyEnforced = policyEnforcedGlobally && policyEnforcedOnAllUsers;
sendPolicyResultToAdmin(
enforcingAdmin,
policyDefinition,
- policyEnforcedGlobally && policyEnforcedOnAllUsers,
// TODO: we're always sending this for now, should properly handle errors.
- REASON_CONFLICTING_ADMIN_POLICY,
+ policyEnforced ? RESULT_SUCCESS : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
UserHandle.USER_ALL);
if (policyState.getPoliciesSetByAdmins().isEmpty()) {
@@ -336,7 +330,7 @@
UserHandle.USER_ALL);
sendPolicyChangedToAdmins(
- policyState.getPoliciesSetByAdmins().keySet(),
+ policyState,
enforcingAdmin,
policyDefinition,
UserHandle.USER_ALL);
@@ -376,7 +370,7 @@
enforcePolicy(
policyDefinition, localPolicyState.getCurrentResolvedPolicy(), userId);
sendPolicyChangedToAdmins(
- localPolicyState.getPoliciesSetByAdmins().keySet(),
+ localPolicyState,
enforcingAdmin,
policyDefinition,
// Even though this is caused by a global policy change, admins who've set
@@ -430,6 +424,42 @@
}
}
+ /**
+ * Returns the policies set by the given admin that share the same {@link PolicyKey#getKey()} as
+ * the provided {@code policyDefinition}.
+ *
+ * <p>For example, getLocalPolicyKeysSetByAdmin(PERMISSION_GRANT, admin) returns all permission
+ * grants set by the given admin.
+ *
+ * <p>Note that this will always return at most one item for policies that do not require
+ * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs
+ * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}).
+ *
+ */
+ @NonNull
+ <V> Set<PolicyKey> getLocalPolicyKeysSetByAdmin(
+ @NonNull PolicyDefinition<V> policyDefinition,
+ @NonNull EnforcingAdmin enforcingAdmin,
+ int userId) {
+ Objects.requireNonNull(policyDefinition);
+ Objects.requireNonNull(enforcingAdmin);
+
+ synchronized (mLock) {
+ if (policyDefinition.isGlobalOnlyPolicy() || !mLocalPolicies.contains(userId)) {
+ return Set.of();
+ }
+ Set<PolicyKey> keys = new HashSet<>();
+ for (PolicyKey key : mLocalPolicies.get(userId).keySet()) {
+ if (key.hasSameKeyAs(policyDefinition.getPolicyKey())
+ && mLocalPolicies.get(userId).get(key).getPoliciesSetByAdmins()
+ .containsKey(enforcingAdmin)) {
+ keys.add(key);
+ }
+ }
+ return keys;
+ }
+ }
+
private <V> boolean hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId) {
if (policyDefinition.isGlobalOnlyPolicy()) {
return false;
@@ -501,7 +531,7 @@
}
private static <V> PolicyState<V> getPolicyState(
- Map<String, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) {
+ Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) {
try {
// This will not throw an exception because policyDefinition is of type V, so unless
// we've created two policies with the same key but different types - we can only have
@@ -523,8 +553,7 @@
}
private <V> void sendPolicyResultToAdmin(
- EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, boolean success,
- int reason, int userId) {
+ EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int result, int userId) {
Intent intent = new Intent(PolicyUpdatesReceiver.ACTION_DEVICE_POLICY_SET_RESULT);
intent.setPackage(admin.getPackageName());
@@ -539,21 +568,14 @@
}
Bundle extras = new Bundle();
- extras.putString(EXTRA_POLICY_KEY, policyDefinition.getPolicyDefinitionKey());
- if (policyDefinition.getCallbackArgs() != null
- && !policyDefinition.getCallbackArgs().isEmpty()) {
- extras.putBundle(EXTRA_POLICY_BUNDLE_KEY, policyDefinition.getCallbackArgs());
- }
+ policyDefinition.getPolicyKey().writeToBundle(extras);
extras.putInt(
EXTRA_POLICY_TARGET_USER_ID,
getTargetUser(admin.getUserId(), userId));
extras.putInt(
- EXTRA_POLICY_SET_RESULT_KEY,
- success ? POLICY_SET_RESULT_SUCCESS : POLICY_SET_RESULT_FAILURE);
+ EXTRA_POLICY_UPDATE_RESULT_KEY,
+ result);
- if (!success) {
- extras.putInt(EXTRA_POLICY_UPDATE_REASON_KEY, reason);
- }
intent.putExtras(extras);
maybeSendIntentToAdminReceivers(intent, UserHandle.of(admin.getUserId()), receivers);
@@ -561,17 +583,21 @@
// TODO(b/261430877): Finalise the decision on which admins to send the updates to.
private <V> void sendPolicyChangedToAdmins(
- Set<EnforcingAdmin> admins,
+ PolicyState<V> policyState,
EnforcingAdmin callingAdmin,
PolicyDefinition<V> policyDefinition,
int userId) {
- for (EnforcingAdmin admin: admins) {
+ for (EnforcingAdmin admin: policyState.getPoliciesSetByAdmins().keySet()) {
// We're sending a separate broadcast for the calling admin with the result.
if (admin.equals(callingAdmin)) {
continue;
}
+ int result = Objects.equals(
+ policyState.getPoliciesSetByAdmins().get(admin),
+ policyState.getCurrentResolvedPolicy())
+ ? RESULT_SUCCESS : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY;
maybeSendOnPolicyChanged(
- admin, policyDefinition, REASON_CONFLICTING_ADMIN_POLICY, userId);
+ admin, policyDefinition, result, userId);
}
}
@@ -592,15 +618,11 @@
}
Bundle extras = new Bundle();
- extras.putString(EXTRA_POLICY_KEY, policyDefinition.getPolicyDefinitionKey());
- if (policyDefinition.getCallbackArgs() != null
- && !policyDefinition.getCallbackArgs().isEmpty()) {
- extras.putBundle(EXTRA_POLICY_BUNDLE_KEY, policyDefinition.getCallbackArgs());
- }
+ policyDefinition.getPolicyKey().writeToBundle(extras);
extras.putInt(
EXTRA_POLICY_TARGET_USER_ID,
getTargetUser(admin.getUserId(), userId));
- extras.putInt(EXTRA_POLICY_UPDATE_REASON_KEY, reason);
+ extras.putInt(EXTRA_POLICY_UPDATE_RESULT_KEY, reason);
intent.putExtras(extras);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -779,14 +801,14 @@
}
private boolean doesAdminHavePolicies(@NonNull EnforcingAdmin enforcingAdmin) {
- for (String policy : mGlobalPolicies.keySet()) {
+ for (PolicyKey policy : mGlobalPolicies.keySet()) {
PolicyState<?> policyState = mGlobalPolicies.get(policy);
if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
return true;
}
}
for (int i = 0; i < mLocalPolicies.size(); i++) {
- for (String policy : mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet()) {
+ for (PolicyKey policy : mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet()) {
PolicyState<?> policyState = mLocalPolicies.get(
mLocalPolicies.keyAt(i)).get(policy);
if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
@@ -880,13 +902,12 @@
if (mLocalPolicies != null) {
for (int i = 0; i < mLocalPolicies.size(); i++) {
int userId = mLocalPolicies.keyAt(i);
- for (Map.Entry<String, PolicyState<?>> policy : mLocalPolicies.get(
+ for (Map.Entry<PolicyKey, PolicyState<?>> policy : mLocalPolicies.get(
userId).entrySet()) {
serializer.startTag(/* namespace= */ null, TAG_LOCAL_POLICY_ENTRY);
serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, userId);
- serializer.attribute(
- /* namespace= */ null, ATTR_POLICY_ID, policy.getKey());
+ policy.getKey().saveToXml(serializer);
serializer.startTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY);
policy.getValue().saveToXml(serializer);
@@ -900,10 +921,10 @@
private void writeGlobalPoliciesInner(TypedXmlSerializer serializer) throws IOException {
if (mGlobalPolicies != null) {
- for (Map.Entry<String, PolicyState<?>> policy : mGlobalPolicies.entrySet()) {
+ for (Map.Entry<PolicyKey, PolicyState<?>> policy : mGlobalPolicies.entrySet()) {
serializer.startTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY);
- serializer.attribute(/* namespace= */ null, ATTR_POLICY_ID, policy.getKey());
+ policy.getKey().saveToXml(serializer);
serializer.startTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY);
policy.getValue().saveToXml(serializer);
@@ -973,8 +994,7 @@
private void readLocalPoliciesInner(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
- String policyKey = parser.getAttributeValue(
- /* namespace= */ null, ATTR_POLICY_ID);
+ PolicyKey policyKey = PolicyDefinition.readPolicyKeyFromXml(parser);
if (!mLocalPolicies.contains(userId)) {
mLocalPolicies.put(userId, new HashMap<>());
}
@@ -989,7 +1009,7 @@
private void readGlobalPoliciesInner(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
- String policyKey = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_ID);
+ PolicyKey policyKey = PolicyDefinition.readPolicyKeyFromXml(parser);
PolicyState<?> adminsPolicy = parseAdminsPolicy(parser);
if (adminsPolicy != null) {
mGlobalPolicies.put(policyKey, adminsPolicy);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f47c330..ce67f3c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1092,13 +1092,13 @@
// (ACTION_DATE_CHANGED), or when manual clock adjustment is made
// (ACTION_TIME_CHANGED)
updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
- final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
+ final int userId = getManagedUserId(mUserManager.getMainUser().getIdentifier());
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(UserHandle.USER_SYSTEM);
+ final int userId = getManagedUserId(mUserManager.getMainUser().getIdentifier());
if (userId >= 0) {
updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
} else {
@@ -8598,9 +8598,20 @@
Preconditions.checkArgument(admin != null);
final CallerIdentity caller = getCallerIdentity();
- // Cannot be called while holding the lock:
- final boolean hasIncompatibleAccountsOrNonAdb =
- hasIncompatibleAccountsOrNonAdbNoLock(caller, userId, admin);
+
+ boolean hasIncompatibleAccountsOrNonAdb =
+ !isAdb(caller) || hasIncompatibleAccountsOnAnyUser();
+
+ if (!hasIncompatibleAccountsOrNonAdb) {
+ synchronized (getLockObject()) {
+ if (!isAdminTestOnlyLocked(admin, userId) && hasAccountsOnAnyUser()) {
+ Slogf.w(LOG_TAG,
+ "Non test-only owner can't be installed with existing accounts.");
+ return false;
+ }
+ }
+ }
+
synchronized (getLockObject()) {
enforceCanSetDeviceOwnerLocked(caller, admin, userId, hasIncompatibleAccountsOrNonAdb);
Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId),
@@ -10202,16 +10213,24 @@
|| isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
final int userHandle = caller.getUserId();
- synchronized (getLockObject()) {
- long id = mInjector.binderClearCallingIdentity();
- try {
- mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
- mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
- } catch (RemoteException re) {
- // Shouldn't happen
- Slog.wtf(LOG_TAG, "Error adding persistent preferred activity", re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ if (isCoexistenceEnabled(caller)) {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(filter),
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
+ activity,
+ userHandle);
+ } else {
+ synchronized (getLockObject()) {
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
+ mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ Slog.wtf(LOG_TAG, "Error adding persistent preferred activity", re);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
}
}
final String activityPackage =
@@ -10231,17 +10250,61 @@
|| isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
final int userHandle = caller.getUserId();
- synchronized (getLockObject()) {
- long id = mInjector.binderClearCallingIdentity();
- try {
- mIPackageManager.clearPackagePersistentPreferredActivities(packageName, userHandle);
- mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
- } catch (RemoteException re) {
- // Shouldn't happen
- Slogf.wtf(
- LOG_TAG, "Error when clearing package persistent preferred activities", re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+
+ if (isCoexistenceEnabled(caller)) {
+ clearPackagePersistentPreferredActivitiesFromPolicyEngine(
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
+ packageName,
+ userHandle);
+ } else {
+ synchronized (getLockObject()) {
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ mIPackageManager.clearPackagePersistentPreferredActivities(packageName,
+ userHandle);
+ mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ Slogf.wtf(
+ LOG_TAG, "Error when clearing package persistent preferred activities",
+ re);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove all persistent intent handler preferences associated with the given package that were
+ * set by this admin, note that is doesn't remove preferences set by other admins for the same
+ * package.
+ */
+ private void clearPackagePersistentPreferredActivitiesFromPolicyEngine(
+ EnforcingAdmin admin, String packageName, int userId) {
+ Set<PolicyKey> keys = mDevicePolicyEngine.getLocalPolicyKeysSetByAdmin(
+ PolicyDefinition.GENERIC_PERSISTENT_PREFERRED_ACTIVITY,
+ admin,
+ userId);
+ for (PolicyKey key : keys) {
+ if (!(key instanceof PersistentPreferredActivityPolicyKey)) {
+ throw new IllegalStateException("PolicyKey for PERSISTENT_PREFERRED_ACTIVITY is not"
+ + "of type PersistentPreferredActivityPolicyKey");
+ }
+ PersistentPreferredActivityPolicyKey parsedKey =
+ (PersistentPreferredActivityPolicyKey) key;
+ IntentFilter filter = Objects.requireNonNull(parsedKey.getFilter());
+
+ ComponentName preferredActivity = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(filter),
+ admin,
+ userId);
+ if (preferredActivity != null
+ && preferredActivity.getPackageName().equals(packageName)) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(filter),
+ admin,
+ userId);
}
}
}
@@ -12167,24 +12230,40 @@
|| isFinancedDeviceOwner(caller)))
|| (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL)));
- final int userId = caller.getUserId();
- synchronized (getLockObject()) {
- long id = mInjector.binderClearCallingIdentity();
- try {
- mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
- } catch (RemoteException re) {
- // Shouldn't happen.
- Slogf.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ if (isCoexistenceEnabled(caller)) {
+ // TODO(b/260573124): Add correct enforcing admin when permission changes are
+ // merged, and don't forget to handle delegates! Enterprise admins assume
+ // component name isn't null.
+ EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ who != null ? who : new ComponentName(callerPackage, "delegate"),
+ caller.getUserId());
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.PACKAGE_UNINSTALL_BLOCKED(packageName),
+ admin,
+ uninstallBlocked,
+ caller.getUserId());
+ } else {
+ final int userId = caller.getUserId();
+ synchronized (getLockObject()) {
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ mIPackageManager.setBlockUninstallForUser(
+ packageName, uninstallBlocked, userId);
+ } catch (RemoteException re) {
+ // Shouldn't happen.
+ Slogf.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ if (uninstallBlocked) {
+ final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ pmi.removeNonSystemPackageSuspensions(packageName, userId);
+ pmi.removeDistractingPackageRestrictions(packageName, userId);
+ pmi.flushPackageRestrictions(userId);
}
}
- if (uninstallBlocked) {
- final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
- pmi.removeNonSystemPackageSuspensions(packageName, userId);
- pmi.removeDistractingPackageRestrictions(packageName, userId);
- pmi.flushPackageRestrictions(userId);
- }
+
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED)
.setAdmin(caller.getPackageName())
@@ -12193,6 +12272,26 @@
.write();
}
+ static void setUninstallBlockedUnchecked(
+ String packageName, boolean uninstallBlocked, int userId) {
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ AppGlobals.getPackageManager().setBlockUninstallForUser(
+ packageName, uninstallBlocked, userId);
+ } catch (RemoteException re) {
+ // Shouldn't happen.
+ Slogf.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
+ }
+ });
+ if (uninstallBlocked) {
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ pmi.removeNonSystemPackageSuspensions(packageName, userId);
+ pmi.removeDistractingPackageRestrictions(packageName, userId);
+ pmi.flushPackageRestrictions(userId);
+ }
+ }
+
@Override
public boolean isUninstallBlocked(ComponentName who, String packageName) {
// This function should return true if and only if the package is blocked by
@@ -14746,14 +14845,10 @@
if (isAdb) {
// If shell command runs after user setup completed check device status. Otherwise, OK.
if (mIsWatch || hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
- // In non-headless system user mode, DO can be setup only if
- // there's no non-system user.
- // In headless system user mode, DO can be setup only if there are
- // two users: the headless system user and the foreground user.
- // If there could be multiple foreground users, this constraint should be modified.
+ // DO can be setup only if there are no users which are neither created by default
+ // nor marked as FOR_TESTING
- int maxNumberOfExistingUsers = isHeadlessSystemUserMode ? 2 : 1;
- if (mUserManager.getUserCount() > maxNumberOfExistingUsers) {
+ if (nonTestNonPrecreatedUsersExist()) {
return STATUS_NONSYSTEM_USER_EXISTS;
}
@@ -14783,6 +14878,17 @@
}
}
+ /**
+ * True if there are any users on the device which were not setup by default (1 usually, 2 for
+ * devices with a headless system user) and also are not marked as FOR_TESTING.
+ */
+ private boolean nonTestNonPrecreatedUsersExist() {
+ int allowedUsers = UserManager.isHeadlessSystemUserMode() ? 2 : 1;
+ return mUserManagerInternal.getUsers(/* excludeDying= */ true).stream()
+ .filter(u -> !u.isForTesting())
+ .count() > allowedUsers;
+ }
+
private int checkDeviceOwnerProvisioningPreCondition(@UserIdInt int callingUserId) {
synchronized (getLockObject()) {
final int deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
@@ -16054,8 +16160,10 @@
wtfIfInLock();
return mInjector.binderWithCleanCallingIdentity(() -> {
- final AccountManager am = AccountManager.get(mContext);
- final Account accounts[] = am.getAccountsAsUser(userId);
+ AccountManager am =
+ mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0)
+ .getSystemService(AccountManager.class);
+ Account[] accounts = am.getAccounts();
if (accounts.length == 0) {
return false;
}
@@ -18169,8 +18277,10 @@
.addAction(turnProfileOnButton)
.addExtras(extras)
.build();
- mInjector.getNotificationManager().notify(
- SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED, notification);
+
+ mInjector.getNotificationManager().notifyAsUser(
+ null, SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED, notification,
+ UserHandle.of(getProfileParentId(profileUserId)));
}
private String getPersonalAppSuspensionButtonText() {
@@ -19537,6 +19647,14 @@
}
@Override
+ public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ setBypassDevicePolicyManagementRoleQualificationStateInternal(
+ /* currentRoleHolder= */ null, /* allowBypass= */ false);
+ }
+
+ @Override
public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ROLE_HOLDERS));
@@ -19550,15 +19668,51 @@
}
private boolean shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal() {
- if (mUserManager.getUserCount() > 1) {
+ if (nonTestNonPrecreatedUsersExist()) {
return false;
}
- AccountManager am = AccountManager.get(mContext);
- Account[] accounts = am.getAccounts();
- if (accounts.length == 0) {
- return true;
+
+
+ return !hasIncompatibleAccountsOnAnyUser();
+ }
+
+ private boolean hasAccountsOnAnyUser() {
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ for (UserInfo user : mUserManagerInternal.getUsers(/* excludeDying= */ true)) {
+ AccountManager am = mContext.createContextAsUser(
+ UserHandle.of(user.id), /* flags= */ 0)
+ .getSystemService(AccountManager.class);
+ Account[] accounts = am.getAccounts();
+ if (accounts.length != 0) {
+ return true;
+ }
+ }
+
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
}
- return !hasIncompatibleAccounts(am, accounts);
+ }
+
+ private boolean hasIncompatibleAccountsOnAnyUser() {
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ for (UserInfo user : mUserManagerInternal.getUsers(/* excludeDying= */ true)) {
+ AccountManager am = mContext.createContextAsUser(
+ UserHandle.of(user.id), /* flags= */ 0)
+ .getSystemService(AccountManager.class);
+ Account[] accounts = am.getAccounts();
+
+ if (hasIncompatibleAccounts(am, accounts)) {
+ return true;
+ }
+ }
+
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
}
private void setBypassDevicePolicyManagementRoleQualificationStateInternal(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PackageSpecificPolicyKey.java b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSpecificPolicyKey.java
new file mode 100644
index 0000000..1665830
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSpecificPolicyKey.java
@@ -0,0 +1,101 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain package in the policy engine's data
+ * structure.
+ */
+final class PackageSpecificPolicyKey extends PolicyKey {
+ private static final String ATTR_POLICY_KEY = "policy-key";
+ private static final String ATTR_PACKAGE_NAME = "package-name";
+ private static final String ATTR_PERMISSION_NAME = "permission-name";
+
+ private final String mPackageName;
+
+ PackageSpecificPolicyKey(String key, String packageName) {
+ super(key);
+ mPackageName = Objects.requireNonNull((packageName));
+ }
+
+ PackageSpecificPolicyKey(String key) {
+ super(key);
+ mPackageName = null;
+ }
+
+ @Nullable
+ String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_POLICY_KEY, mKey);
+ serializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
+ }
+
+ @Override
+ PackageSpecificPolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String policyKey = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_KEY);
+ String packageName = parser.getAttributeValue(/* namespace= */ null, ATTR_PACKAGE_NAME);
+ String permissionName = parser.getAttributeValue(
+ /* namespace= */ null, ATTR_PERMISSION_NAME);
+ return new PackageSpecificPolicyKey(policyKey, packageName);
+ }
+
+ @Override
+ void writeToBundle(Bundle bundle) {
+ super.writeToBundle(bundle);
+ Bundle extraPolicyParams = new Bundle();
+ extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
+ bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PackageSpecificPolicyKey other = (PackageSpecificPolicyKey) o;
+ return Objects.equals(mKey, other.mKey)
+ && Objects.equals(mPackageName, other.mPackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mKey, mPackageName);
+ }
+
+ @Override
+ public String toString() {
+ return "mPolicyKey= " + mKey + "; mPackageName= " + mPackageName;
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PermissionGrantStatePolicyKey.java b/services/devicepolicy/java/com/android/server/devicepolicy/PermissionGrantStatePolicyKey.java
new file mode 100644
index 0000000..b7d805e
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PermissionGrantStatePolicyKey.java
@@ -0,0 +1,113 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a PermissionGrantState policy in the policy engine's data structure.
+ */
+final class PermissionGrantStatePolicyKey extends PolicyKey {
+ private static final String ATTR_POLICY_KEY = "policy-key";
+ private static final String ATTR_PACKAGE_NAME = "package-name";
+ private static final String ATTR_PERMISSION_NAME = "permission-name";
+
+ private final String mPackageName;
+ private final String mPermissionName;
+
+ PermissionGrantStatePolicyKey(String key, String packageName, String permissionName) {
+ super(key);
+ mPackageName = Objects.requireNonNull((packageName));
+ mPermissionName = Objects.requireNonNull((permissionName));
+ }
+
+ PermissionGrantStatePolicyKey(String key) {
+ super(key);
+ mPackageName = null;
+ mPermissionName = null;
+ }
+
+ @Nullable
+ String getPackageName() {
+ return mPackageName;
+ }
+
+ @Nullable
+ String getPermissionName() {
+ return mPermissionName;
+ }
+
+ @Override
+ void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_POLICY_KEY, mKey);
+ serializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
+ serializer.attribute(/* namespace= */ null, ATTR_PERMISSION_NAME, mPermissionName);
+ }
+
+ @Override
+ PermissionGrantStatePolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String policyKey = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_KEY);
+ String packageName = parser.getAttributeValue(/* namespace= */ null, ATTR_PACKAGE_NAME);
+ String permissionName = parser.getAttributeValue(
+ /* namespace= */ null, ATTR_PERMISSION_NAME);
+ return new PermissionGrantStatePolicyKey(policyKey, packageName, permissionName);
+ }
+
+ @Override
+ void writeToBundle(Bundle bundle) {
+ super.writeToBundle(bundle);
+ Bundle extraPolicyParams = new Bundle();
+ extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
+ extraPolicyParams.putString(EXTRA_PERMISSION_NAME, mPermissionName);
+ bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PermissionGrantStatePolicyKey other = (PermissionGrantStatePolicyKey) o;
+ return Objects.equals(mKey, other.mKey)
+ && Objects.equals(mPackageName, other.mPackageName)
+ && Objects.equals(mPermissionName, other.mPermissionName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mKey, mPackageName, mPermissionName);
+ }
+
+ @Override
+ public String toString() {
+ return "mPolicyKey= " + mKey + "; mPackageName= " + mPackageName + "; mPermissionName= "
+ + mPermissionName;
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersistentPreferredActivityPolicyKey.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersistentPreferredActivityPolicyKey.java
new file mode 100644
index 0000000..f8c07595
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersistentPreferredActivityPolicyKey.java
@@ -0,0 +1,99 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_INTENT_FILTER;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+
+import android.annotation.Nullable;
+import android.content.IntentFilter;
+import android.os.Bundle;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.IntentResolver;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a PersistentPreferredActivity policy in the policy engine's data
+ * structure.
+ */
+final class PersistentPreferredActivityPolicyKey extends PolicyKey {
+ private static final String ATTR_POLICY_KEY = "policy-key";
+ private IntentFilter mFilter;
+
+ PersistentPreferredActivityPolicyKey(String policyKey, IntentFilter filter) {
+ super(policyKey);
+ mFilter = Objects.requireNonNull((filter));
+ }
+
+ PersistentPreferredActivityPolicyKey(String policyKey) {
+ super(policyKey);
+ mFilter = null;
+ }
+
+ @Nullable
+ IntentFilter getFilter() {
+ return mFilter;
+ }
+
+ @Override
+ void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_POLICY_KEY, mKey);
+ mFilter.writeToXml(serializer);
+ }
+
+ @Override
+ PersistentPreferredActivityPolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String policyKey = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_KEY);
+ IntentFilter filter = new IntentFilter();
+ filter.readFromXml(parser);
+ return new PersistentPreferredActivityPolicyKey(policyKey, filter);
+ }
+
+ @Override
+ void writeToBundle(Bundle bundle) {
+ super.writeToBundle(bundle);
+ Bundle extraPolicyParams = new Bundle();
+ extraPolicyParams.putParcelable(EXTRA_INTENT_FILTER, mFilter);
+ bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PersistentPreferredActivityPolicyKey other = (PersistentPreferredActivityPolicyKey) o;
+ return Objects.equals(mKey, other.mKey)
+ && IntentResolver.filterEquals(mFilter, other.mFilter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mKey, mFilter);
+ }
+
+ @Override
+ public String toString() {
+ return "mKey= " + mKey + "; mFilter= " + mFilter;
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index cfb3db0..ab1658f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -19,9 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
-import android.app.admin.PolicyUpdatesReceiver;
+import android.content.ComponentName;
import android.content.Context;
-import android.os.Bundle;
+import android.content.IntentFilter;
import com.android.internal.util.function.QuadFunction;
import com.android.modules.utils.TypedXmlPullParser;
@@ -47,27 +47,25 @@
private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(false, true));
- private static final String ATTR_POLICY_KEY = "policy-key";
- private static final String ATTR_POLICY_DEFINITION_KEY = "policy-type-key";
- private static final String ATTR_CALLBACK_ARGS_SIZE = "size";
- private static final String ATTR_CALLBACK_ARGS_KEY = "key";
- private static final String ATTR_CALLBACK_ARGS_VALUE = "value";
-
+ private static final MostRestrictive<Boolean> TRUE_MORE_RESTRICTIVE = new MostRestrictive<>(
+ List.of(true, false));
static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
- DevicePolicyManager.AUTO_TIMEZONE_POLICY,
+ new DefaultPolicyKey(DevicePolicyManager.AUTO_TIMEZONE_POLICY),
// auto timezone is enabled by default, hence disabling it is more restrictive.
FALSE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
- (Boolean value, Context context, Integer userId, Bundle args) ->
+ (Boolean value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setAutoTimezoneEnabled(value, context),
new BooleanPolicySerializer());
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
// actual permission grant policy with the correct arguments (packageName and permission name)
// when reading the policies from xml.
- private static final PolicyDefinition<Integer> PERMISSION_GRANT_NO_ARGS =
- new PolicyDefinition<>(DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY,
+ static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
+ new PolicyDefinition<>(
+ new PermissionGrantStatePolicyKey(
+ DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY),
// TODO: is this really the best mechanism, what makes denied more
// restrictive than
// granted?
@@ -79,71 +77,125 @@
PolicyEnforcerCallbacks::setPermissionGrantState,
new IntegerPolicySerializer());
+ /**
+ * Passing in {@code null} for {@code packageName} or {@code permissionName} will return a
+ * {@link #GENERIC_PERMISSION_GRANT}.
+ */
static PolicyDefinition<Integer> PERMISSION_GRANT(
- @NonNull String packageName, @NonNull String permission) {
- Bundle callbackArgs = new Bundle();
- callbackArgs.putString(PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME, packageName);
- callbackArgs.putString(PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME, permission);
- return PERMISSION_GRANT_NO_ARGS.setArgs(
- DevicePolicyManager.PERMISSION_GRANT_POLICY(packageName, permission), callbackArgs);
+ @NonNull String packageName, @NonNull String permissionName) {
+ if (packageName == null || permissionName == null) {
+ return GENERIC_PERMISSION_GRANT;
+ }
+ return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
+ new PermissionGrantStatePolicyKey(
+ DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY,
+ packageName,
+ permissionName));
}
static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
- DevicePolicyManager.LOCK_TASK_POLICY,
+ new DefaultPolicyKey(DevicePolicyManager.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
// TODO(b/258166155): add correct device lock role name
EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
- (LockTaskPolicy value, Context context, Integer userId, Bundle args) ->
+ (LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setLockTask(value, context, userId),
new LockTaskPolicy.LockTaskPolicySerializer());
static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES = new PolicyDefinition<>(
- DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES,
+ new DefaultPolicyKey(DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY),
new SetUnion<>(),
- (Set<String> value, Context context, Integer userId, Bundle args) ->
+ (Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
new SetPolicySerializer<>());
+ // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
+ // actual permission grant policy with the correct arguments (packageName and permission name)
+ // when reading the policies from xml.
+ static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
+ new PolicyDefinition<>(
+ new PersistentPreferredActivityPolicyKey(
+ DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
+ new TopPriority<>(List.of(
+ // TODO(b/258166155): add correct device lock role name
+ EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.DPC_AUTHORITY)),
+ POLICY_FLAG_LOCAL_ONLY_POLICY,
+ PolicyEnforcerCallbacks::addPersistentPreferredActivity,
+ new ComponentNamePolicySerializer());
+
+ /**
+ * Passing in {@code null} for {@code intentFilter} will return
+ * {@link #GENERIC_PERSISTENT_PREFERRED_ACTIVITY}.
+ */
+ static PolicyDefinition<ComponentName> PERSISTENT_PREFERRED_ACTIVITY(
+ IntentFilter intentFilter) {
+ if (intentFilter == null) {
+ return GENERIC_PERSISTENT_PREFERRED_ACTIVITY;
+ }
+ return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
+ new PersistentPreferredActivityPolicyKey(
+ DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY, intentFilter));
+ }
+
+ // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
+ // actual uninstall blocked policy with the correct arguments (i.e. packageName)
+ // when reading the policies from xml.
+ static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
+ new PolicyDefinition<>(
+ new PackageSpecificPolicyKey(
+ DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY),
+ TRUE_MORE_RESTRICTIVE,
+ POLICY_FLAG_LOCAL_ONLY_POLICY,
+ PolicyEnforcerCallbacks::setUninstallBlocked,
+ new BooleanPolicySerializer());
+
+ /**
+ * Passing in {@code null} for {@code packageName} will return
+ * {@link #GENERIC_PACKAGE_UNINSTALL_BLOCKED}.
+ */
+ static PolicyDefinition<Boolean> PACKAGE_UNINSTALL_BLOCKED(
+ String packageName) {
+ if (packageName == null) {
+ return GENERIC_PACKAGE_UNINSTALL_BLOCKED;
+ }
+ return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
+ new PackageSpecificPolicyKey(
+ DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
+ }
+
private static final Map<String, PolicyDefinition<?>> sPolicyDefinitions = Map.of(
DevicePolicyManager.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
- DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY, PERMISSION_GRANT_NO_ARGS,
+ DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY, GENERIC_PERMISSION_GRANT,
DevicePolicyManager.LOCK_TASK_POLICY, LOCK_TASK,
- DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES, USER_CONTROLLED_DISABLED_PACKAGES
+ DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+ USER_CONTROLLED_DISABLED_PACKAGES,
+ DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ GENERIC_PERSISTENT_PREFERRED_ACTIVITY,
+ DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, GENERIC_PACKAGE_UNINSTALL_BLOCKED
);
- private final String mPolicyKey;
- private final String mPolicyDefinitionKey;
+ private final PolicyKey mPolicyKey;
private final ResolutionMechanism<V> mResolutionMechanism;
private final int mPolicyFlags;
// A function that accepts policy to apple, context, userId, callback arguments, and returns
// true if the policy has been enforced successfully.
- private final QuadFunction<V, Context, Integer, Bundle, Boolean> mPolicyEnforcerCallback;
- private final Bundle mCallbackArgs;
+ private final QuadFunction<V, Context, Integer, PolicyKey, Boolean> mPolicyEnforcerCallback;
private final PolicySerializer<V> mPolicySerializer;
- private PolicyDefinition<V> setArgs(String key, Bundle callbackArgs) {
- return new PolicyDefinition<>(key, mPolicyDefinitionKey, mResolutionMechanism,
- mPolicyFlags, mPolicyEnforcerCallback, mPolicySerializer, callbackArgs);
+ private PolicyDefinition<V> createPolicyDefinition(PolicyKey key) {
+ return new PolicyDefinition<>(key, mResolutionMechanism, mPolicyFlags,
+ mPolicyEnforcerCallback, mPolicySerializer);
}
@NonNull
- String getPolicyKey() {
+ PolicyKey getPolicyKey() {
return mPolicyKey;
}
- @NonNull
- String getPolicyDefinitionKey() {
- return mPolicyDefinitionKey;
- }
-
- @Nullable
- Bundle getCallbackArgs() {
- return mCallbackArgs;
- }
-
/**
* Returns {@code true} if the policy is a global policy by nature and can't be applied locally.
*/
@@ -164,7 +216,7 @@
}
boolean enforcePolicy(@Nullable V value, Context context, int userId) {
- return mPolicyEnforcerCallback.apply(value, context, userId, mCallbackArgs);
+ return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
}
/**
@@ -172,93 +224,54 @@
* {@link Object#equals} implementation.
*/
private PolicyDefinition(
- String key,
+ PolicyKey key,
ResolutionMechanism<V> resolutionMechanism,
- QuadFunction<V, Context, Integer, Bundle, Boolean> policyEnforcerCallback,
+ QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
this(key, resolutionMechanism, POLICY_FLAG_NONE, policyEnforcerCallback, policySerializer);
}
/**
- * Callers must ensure that {@code policyType} have implemented an appropriate
- * {@link Object#equals} implementation.
+ * Callers must ensure that custom {@code policyKeys} and {@code V} have an appropriate
+ * {@link Object#equals} and {@link Object#hashCode()} implementation.
*/
private PolicyDefinition(
- String key,
+ PolicyKey policyKey,
ResolutionMechanism<V> resolutionMechanism,
int policyFlags,
- QuadFunction<V, Context, Integer, Bundle, Boolean> policyEnforcerCallback,
+ QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
- this(key, key, resolutionMechanism, policyFlags, policyEnforcerCallback,
- policySerializer, /* callbackArs= */ null);
- }
-
- /**
- * Callers must ensure that {@code policyType} have implemented an appropriate
- * {@link Object#equals} implementation.
- */
- private PolicyDefinition(
- String policyKey,
- String policyDefinitionKey,
- ResolutionMechanism<V> resolutionMechanism,
- int policyFlags,
- QuadFunction<V, Context, Integer, Bundle, Boolean> policyEnforcerCallback,
- PolicySerializer<V> policySerializer,
- Bundle callbackArgs) {
mPolicyKey = policyKey;
- mPolicyDefinitionKey = policyDefinitionKey;
mResolutionMechanism = resolutionMechanism;
mPolicyFlags = policyFlags;
mPolicyEnforcerCallback = policyEnforcerCallback;
mPolicySerializer = policySerializer;
- mCallbackArgs = callbackArgs;
// TODO: maybe use this instead of manually adding to the map
// sPolicyDefinitions.put(policyDefinitionKey, this);
}
void saveToXml(TypedXmlSerializer serializer) throws IOException {
- serializer.attribute(/* namespace= */ null, ATTR_POLICY_KEY, mPolicyKey);
- serializer.attribute(
- /* namespace= */ null, ATTR_POLICY_DEFINITION_KEY, mPolicyDefinitionKey);
- serializer.attributeInt(
- /* namespace= */ null, ATTR_CALLBACK_ARGS_SIZE,
- mCallbackArgs == null ? 0 : mCallbackArgs.size());
- if (mCallbackArgs != null) {
- int i = 0;
- for (String key : mCallbackArgs.keySet()) {
- serializer.attribute(/* namespace= */ null,
- ATTR_CALLBACK_ARGS_KEY + i, key);
- serializer.attribute(/* namespace= */ null,
- ATTR_CALLBACK_ARGS_VALUE + i, mCallbackArgs.getString(key));
- i++;
- }
- }
+ // TODO: here and elsewhere, add tags to ensure attributes aren't overridden by duplication.
+ mPolicyKey.saveToXml(serializer);
}
static <V> PolicyDefinition<V> readFromXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
- String policyKey = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_KEY);
- String policyDefinitionKey = parser.getAttributeValue(
- /* namespace= */ null, ATTR_POLICY_DEFINITION_KEY);
- int size = parser.getAttributeInt(/* namespace= */ null, ATTR_CALLBACK_ARGS_SIZE);
- Bundle callbackArgs = new Bundle();
-
- for (int i = 0; i < size; i++) {
- String key = parser.getAttributeValue(
- /* namespace= */ null, ATTR_CALLBACK_ARGS_KEY + i);
- String value = parser.getAttributeValue(
- /* namespace= */ null, ATTR_CALLBACK_ARGS_VALUE + i);
- callbackArgs.putString(key, value);
- }
-
// TODO: can we avoid casting?
- if (callbackArgs.isEmpty()) {
- return (PolicyDefinition<V>) sPolicyDefinitions.get(policyDefinitionKey);
- } else {
- return (PolicyDefinition<V>) sPolicyDefinitions.get(policyDefinitionKey).setArgs(
- policyKey, callbackArgs);
- }
+ PolicyKey policyKey = readPolicyKeyFromXml(parser);
+ PolicyDefinition<V> genericPolicyDefinition =
+ (PolicyDefinition<V>) sPolicyDefinitions.get(policyKey.mKey);
+ return genericPolicyDefinition.createPolicyDefinition(policyKey);
+ }
+
+ static <V> PolicyKey readPolicyKeyFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ // TODO: can we avoid casting?
+ PolicyKey policyKey = DefaultPolicyKey.readGenericPolicyKeyFromXml(parser);
+ PolicyDefinition<V> genericPolicyDefinition =
+ (PolicyDefinition<V>) sPolicyDefinitions.get(policyKey.mKey);
+ return genericPolicyDefinition.mPolicyKey.readFromXml(parser);
}
void savePolicyValueToXml(TypedXmlSerializer serializer, String attributeName, V value)
@@ -273,8 +286,7 @@
@Override
public String toString() {
- return "PolicyDefinition { mPolicyKey= " + mPolicyKey + ", mPolicyDefinitionKey= "
- + mPolicyDefinitionKey + ", mResolutionMechanism= " + mResolutionMechanism
- + ", mCallbackArgs= " + mCallbackArgs + ", mPolicyFlags= " + mPolicyFlags + " }";
+ return "PolicyDefinition{ mPolicyKey= " + mPolicyKey + ", mResolutionMechanism= "
+ + mResolutionMechanism + ", mPolicyFlags= " + mPolicyFlags + " }";
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 5664d2b..e2aa23d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -18,17 +18,21 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
-import android.app.admin.PolicyUpdatesReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
-import android.os.Bundle;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.permission.AdminPermissionControlParams;
import android.permission.PermissionControllerManager;
import android.provider.Settings;
+import android.util.Slog;
import com.android.server.LocalServices;
import com.android.server.utils.Slogf;
@@ -58,19 +62,15 @@
static boolean setPermissionGrantState(
@Nullable Integer grantState, @NonNull Context context, int userId,
- @NonNull Bundle args) {
+ @NonNull PolicyKey policyKey) {
return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
- if (args == null
- || !args.containsKey(PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME)
- || !args.containsKey(PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME)) {
- throw new IllegalArgumentException("Package name and permission name must be "
- + "provided as arguments.");
+ if (!(policyKey instanceof PermissionGrantStatePolicyKey)) {
+ throw new IllegalArgumentException("policyKey is not of type "
+ + "PermissionGrantStatePolicyKey");
}
-
- String packageName = args.getString(PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME);
- String permissionName = args.getString(PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME);
- Objects.requireNonNull(packageName);
- Objects.requireNonNull(permissionName);
+ PermissionGrantStatePolicyKey parsedKey = (PermissionGrantStatePolicyKey) policyKey;
+ Objects.requireNonNull(parsedKey.getPermissionName());
+ Objects.requireNonNull(parsedKey.getPackageName());
Objects.requireNonNull(context);
int value = grantState == null
@@ -81,7 +81,7 @@
// TODO: remove canAdminGrantSensorPermissions once we expose a new method in
// permissionController that doesn't need it.
AdminPermissionControlParams permissionParams = new AdminPermissionControlParams(
- packageName, permissionName, value,
+ parsedKey.getPackageName(), parsedKey.getPermissionName(), value,
/* canAdminGrantSensorPermissions= */ true);
getPermissionControllerManager(context, UserHandle.of(userId))
// TODO: remove callingPackage param and stop passing context.getPackageName()
@@ -150,4 +150,51 @@
packages == null ? null : packages.stream().toList()));
return true;
}
+
+ static boolean addPersistentPreferredActivity(
+ @Nullable ComponentName preferredActivity, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ if (!(policyKey instanceof PersistentPreferredActivityPolicyKey)) {
+ throw new IllegalArgumentException("policyKey is not of type "
+ + "PersistentPreferredActivityPolicyKey");
+ }
+ PersistentPreferredActivityPolicyKey parsedKey =
+ (PersistentPreferredActivityPolicyKey) policyKey;
+ IntentFilter filter = Objects.requireNonNull(parsedKey.getFilter());
+
+ IPackageManager packageManager = AppGlobals.getPackageManager();
+ if (preferredActivity != null) {
+ packageManager.addPersistentPreferredActivity(
+ filter, preferredActivity, userId);
+ } else {
+ packageManager.clearPersistentPreferredActivity(filter, userId);
+ }
+ packageManager.flushPackageRestrictionsAsUser(userId);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ Slog.wtf(LOG_TAG, "Error adding/removing persistent preferred activity", re);
+ }
+ });
+ return true;
+ }
+
+ static boolean setUninstallBlocked(
+ @Nullable Boolean uninstallBlocked, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
+ return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
+ if (!(policyKey instanceof PackageSpecificPolicyKey)) {
+ throw new IllegalArgumentException("policyKey is not of type "
+ + "PackageSpecificPolicyKey");
+ }
+ PackageSpecificPolicyKey parsedKey = (PackageSpecificPolicyKey) policyKey;
+ String packageName = Objects.requireNonNull(parsedKey.getPackageName());
+ DevicePolicyManagerService.setUninstallBlockedUnchecked(
+ packageName,
+ uninstallBlocked != null && uninstallBlocked,
+ userId);
+ return true;
+ }));
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyKey.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyKey.java
new file mode 100644
index 0000000..571f0ee
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyKey.java
@@ -0,0 +1,81 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Abstract class used to identify a policy in the policy engine's data structure.
+ */
+abstract class PolicyKey {
+ private static final String ATTR_GENERIC_POLICY_KEY = "generic-policy-key";
+
+ protected final String mKey;
+
+ PolicyKey(String policyKey) {
+ mKey = Objects.requireNonNull(policyKey);
+ }
+
+ String getKey() {
+ return mKey;
+ }
+
+ boolean hasSameKeyAs(PolicyKey other) {
+ if (other == null) {
+ return false;
+ }
+ return mKey.equals(other.mKey);
+ }
+
+ void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_GENERIC_POLICY_KEY, mKey);
+ }
+
+ PolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ // No need to read anything
+ return this;
+ }
+
+ void writeToBundle(Bundle bundle) {
+ bundle.putString(EXTRA_POLICY_KEY, mKey);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PolicyKey other = (PolicyKey) o;
+ return Objects.equals(mKey, other.mKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mKey);
+ }
+}
diff --git a/services/java/com/android/server/BootUserInitializer.java b/services/java/com/android/server/BootUserInitializer.java
index deebfc7..3d71739 100644
--- a/services/java/com/android/server/BootUserInitializer.java
+++ b/services/java/com/android/server/BootUserInitializer.java
@@ -17,7 +17,6 @@
import android.annotation.UserIdInt;
import android.content.ContentResolver;
-import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -27,8 +26,6 @@
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
-import java.util.List;
-
/**
* Class responsible for booting the device in the proper user on headless system user mode.
*
@@ -56,50 +53,18 @@
// this class or the setup wizard app
provisionHeadlessSystemUser();
- UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
- t.traceBegin("get-existing-users");
- List<UserInfo> existingUsers = um.getUsers(/* excludeDying= */ true);
- t.traceEnd();
-
- Slogf.d(TAG, "%d existing users", existingUsers.size());
-
- int initialUserId = UserHandle.USER_NULL;
-
- for (int i = 0; i < existingUsers.size(); i++) {
- UserInfo user = existingUsers.get(i);
- if (DEBUG) {
- Slogf.d(TAG, "User at position %d: %s", i, user.toFullString());
- }
- if (user.id != UserHandle.USER_SYSTEM && user.isFull()) {
- if (DEBUG) {
- Slogf.d(TAG, "Found initial user: %d", user.id);
- }
- initialUserId = user.id;
- break;
- }
- }
-
- if (initialUserId == UserHandle.USER_NULL) {
- Slogf.d(TAG, "Creating initial user");
- t.traceBegin("create-initial-user");
- try {
- int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN;
- // TODO(b/204091126): proper name for user
- UserInfo newUser = um.createUserEvenWhenDisallowed("Real User",
- UserManager.USER_TYPE_FULL_SECONDARY, flags,
- /* disallowedPackages= */ null, /* token= */ null);
- Slogf.i(TAG, "Created initial user: %s", newUser.toFullString());
- initialUserId = newUser.id;
- } catch (Exception e) {
- Slogf.wtf(TAG, "failed to created initial user", e);
- return;
- } finally {
- t.traceEnd(); // create-initial-user
- }
- }
-
unlockSystemUser(t);
- switchToInitialUser(initialUserId);
+
+ try {
+ t.traceBegin("getBootUser");
+ int bootUser = LocalServices.getService(UserManagerInternal.class).getBootUser();
+ t.traceEnd();
+ t.traceBegin("switchToBootUser-" + bootUser);
+ switchToBootUser(bootUser);
+ t.traceEnd();
+ } catch (UserManager.CheckedUserOperationException e) {
+ Slogf.wtf(TAG, "Failed to created boot user", e);
+ }
}
/* TODO(b/261791491): STOPSHIP - SUW should be responsible for this. */
@@ -152,12 +117,12 @@
}
}
- private void switchToInitialUser(@UserIdInt int initialUserId) {
- Slogf.i(TAG, "Switching to initial user %d", initialUserId);
- boolean started = mAms.startUserInForegroundWithListener(initialUserId,
+ private void switchToBootUser(@UserIdInt int bootUserId) {
+ Slogf.i(TAG, "Switching to boot user %d", bootUserId);
+ boolean started = mAms.startUserInForegroundWithListener(bootUserId,
/* unlockListener= */ null);
if (!started) {
- Slogf.wtf(TAG, "Failed to start user %d in foreground", initialUserId);
+ Slogf.wtf(TAG, "Failed to start user %d in foreground", bootUserId);
}
}
}
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 1bd5031..ae8dd41 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -271,22 +271,22 @@
private ConversationChannel getConversationChannel(String packageName, int userId,
String shortcutId, ConversationInfo conversationInfo) {
ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
- return getConversationChannel(shortcutInfo, conversationInfo);
+ return getConversationChannel(
+ shortcutInfo, conversationInfo, packageName, userId, shortcutId);
}
@Nullable
private ConversationChannel getConversationChannel(ShortcutInfo shortcutInfo,
- ConversationInfo conversationInfo) {
+ ConversationInfo conversationInfo, String packageName, int userId, String shortcutId) {
if (conversationInfo == null || conversationInfo.isDemoted()) {
return null;
}
if (shortcutInfo == null) {
- Slog.e(TAG, " Shortcut no longer found");
+ Slog.e(TAG, "Shortcut no longer found");
+ mInjector.getBackgroundExecutor().execute(
+ () -> removeConversations(packageName, userId, Set.of(shortcutId)));
return null;
}
- String packageName = shortcutInfo.getPackage();
- String shortcutId = shortcutInfo.getId();
- int userId = shortcutInfo.getUserId();
int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
NotificationChannel parentChannel =
mNotificationManagerInternal.getNotificationChannel(packageName, uid,
@@ -1130,30 +1130,33 @@
public void onShortcutsRemoved(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
mInjector.getBackgroundExecutor().execute(() -> {
- int uid = Process.INVALID_UID;
- try {
- uid = mContext.getPackageManager().getPackageUidAsUser(
- packageName, user.getIdentifier());
- } catch (PackageManager.NameNotFoundException e) {
- Slog.e(TAG, "Package not found: " + packageName, e);
- }
- PackageData packageData = getPackage(packageName, user.getIdentifier());
- Set<String> shortcutIds = new HashSet<>();
+ HashSet<String> shortcutIds = new HashSet<>();
for (ShortcutInfo shortcutInfo : shortcuts) {
- if (packageData != null) {
- if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutInfo.getId());
- packageData.deleteDataForConversation(shortcutInfo.getId());
- }
shortcutIds.add(shortcutInfo.getId());
}
- if (uid != Process.INVALID_UID) {
- mNotificationManagerInternal.onConversationRemoved(
- packageName, uid, shortcutIds);
- }
+ removeConversations(packageName, user.getIdentifier(), shortcutIds);
});
}
}
+ private void removeConversations(
+ @NonNull String packageName, @NonNull int userId, @NonNull Set<String> shortcutIds) {
+ PackageData packageData = getPackage(packageName, userId);
+ if (packageData != null) {
+ for (String shortcutId : shortcutIds) {
+ if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutId);
+ packageData.deleteDataForConversation(shortcutId);
+ }
+ }
+ try {
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
+ packageName, userId);
+ mNotificationManagerInternal.onConversationRemoved(packageName, uid, shortcutIds);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Package not found when removing conversation: " + packageName, e);
+ }
+ }
+
/** Listener for the notifications and their settings changes. */
private class NotificationListener extends NotificationListenerService {
@@ -1349,9 +1352,11 @@
}
private void updateConversationStoreThenNotifyListeners(ConversationStore cs,
- ConversationInfo modifiedConv, ShortcutInfo shortcutInfo) {
+ ConversationInfo modifiedConv, @NonNull ShortcutInfo shortcutInfo) {
cs.addOrUpdate(modifiedConv);
- ConversationChannel channel = getConversationChannel(shortcutInfo, modifiedConv);
+ ConversationChannel channel = getConversationChannel(
+ shortcutInfo, modifiedConv, shortcutInfo.getPackage(), shortcutInfo.getUserId(),
+ shortcutInfo.getId());
if (channel != null) {
notifyConversationsListeners(Arrays.asList(channel));
}
diff --git a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
index dbc0da7..c8797e2 100644
--- a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.annotation.UserIdInt;
import android.app.job.JobScheduler;
import android.content.Context;
@@ -31,6 +33,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
@@ -45,14 +49,20 @@
private BackupManagerConstants mConstants;
private ShadowJobScheduler mShadowJobScheduler;
+ @Mock
+ private UserBackupManagerService mUserBackupManagerService;
+
@UserIdInt private int mUserOneId;
@UserIdInt private int mUserTwoId;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mConstants = new BackupManagerConstants(Handler.getMain(), mContext.getContentResolver());
mConstants.start();
+ when(mUserBackupManagerService.getConstants()).thenReturn(mConstants);
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(true);
mShadowJobScheduler = Shadows.shadowOf(mContext.getSystemService(JobScheduler.class));
@@ -69,8 +79,8 @@
@Test
public void testSchedule_afterScheduling_jobExists() {
- FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
- FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
+ FullBackupJob.schedule(mUserTwoId, mContext, 0, mUserBackupManagerService);
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNotNull();
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNotNull();
@@ -78,18 +88,34 @@
@Test
public void testCancel_afterCancelling_jobDoesntExist() {
- FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
- FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
+ FullBackupJob.schedule(mUserTwoId, mContext, 0, mUserBackupManagerService);
FullBackupJob.cancel(mUserOneId, mContext);
FullBackupJob.cancel(mUserTwoId, mContext);
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNull();
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNull();
}
+
+ @Test
+ public void testSchedule_isNoopIfDisabled() {
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(false);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
+
+ assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNull();
+ }
+
+ @Test
+ public void testSchedule_schedulesJobIfEnabled() {
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(true);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
+
+ assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNotNull();
+ }
//
@Test
public void testSchedule_onlySchedulesForRequestedUser() {
- FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNotNull();
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNull();
@@ -97,8 +123,8 @@
//
@Test
public void testCancel_onlyCancelsForRequestedUser() {
- FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
- FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+ FullBackupJob.schedule(mUserOneId, mContext, 0, mUserBackupManagerService);
+ FullBackupJob.schedule(mUserTwoId, mContext, 0, mUserBackupManagerService);
FullBackupJob.cancel(mUserOneId, mContext);
assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNull();
diff --git a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
index 1c5fac2..712ac55 100644
--- a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.Handler;
@@ -30,6 +32,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@@ -41,14 +45,20 @@
private Context mContext;
private BackupManagerConstants mConstants;
+ @Mock
+ private UserBackupManagerService mUserBackupManagerService;
+
@UserIdInt private int mUserOneId;
@UserIdInt private int mUserTwoId;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mConstants = new BackupManagerConstants(Handler.getMain(), mContext.getContentResolver());
mConstants.start();
+ when(mUserBackupManagerService.getConstants()).thenReturn(mConstants);
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(true);
mUserOneId = UserHandle.USER_SYSTEM;
mUserTwoId = mUserOneId + 1;
@@ -62,6 +72,22 @@
}
@Test
+ public void testSchedule_isNoopIfDisabled() {
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(false);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
+
+ assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
+ }
+
+ @Test
+ public void testSchedule_schedulesJobIfEnabled() {
+ when(mUserBackupManagerService.isFrameworkSchedulingEnabled()).thenReturn(true);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
+
+ assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isTrue();
+ }
+
+ @Test
public void testIsScheduled_beforeScheduling_returnsFalse() {
assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isFalse();
@@ -69,8 +95,8 @@
@Test
public void testIsScheduled_afterScheduling_returnsTrue() {
- KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
- KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
+ KeyValueBackupJob.schedule(mUserTwoId, mContext, mUserBackupManagerService);
assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isTrue();
assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isTrue();
@@ -78,8 +104,8 @@
@Test
public void testIsScheduled_afterCancelling_returnsFalse() {
- KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
- KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
+ KeyValueBackupJob.schedule(mUserTwoId, mContext, mUserBackupManagerService);
KeyValueBackupJob.cancel(mUserOneId, mContext);
KeyValueBackupJob.cancel(mUserTwoId, mContext);
@@ -89,7 +115,7 @@
@Test
public void testIsScheduled_afterScheduling_returnsTrueOnlyForScheduledUser() {
- KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isTrue();
assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isFalse();
@@ -97,8 +123,8 @@
@Test
public void testIsScheduled_afterCancelling_returnsFalseOnlyForCancelledUser() {
- KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
- KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
+ KeyValueBackupJob.schedule(mUserOneId, mContext, mUserBackupManagerService);
+ KeyValueBackupJob.schedule(mUserTwoId, mContext, mUserBackupManagerService);
KeyValueBackupJob.cancel(mUserOneId, mContext);
assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 2878743..02e0bbf 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -1381,8 +1381,8 @@
* BackupManagerConstants)} that throws an {@link IllegalArgumentException}.
*/
public static void schedule(int userId, Context ctx, long delay,
- BackupManagerConstants constants) {
- ShadowKeyValueBackupJob.schedule(userId, ctx, delay, constants);
+ UserBackupManagerService userBackupManagerService) {
+ ShadowKeyValueBackupJob.schedule(userId, ctx, delay, userBackupManagerService);
throw new IllegalArgumentException();
}
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
index f90ea6a..d66f6ef 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
@@ -21,6 +21,7 @@
import com.android.server.backup.BackupManagerConstants;
import com.android.server.backup.KeyValueBackupJob;
+import com.android.server.backup.UserBackupManagerService;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -35,7 +36,7 @@
@Implementation
protected static void schedule(int userId, Context ctx, long delay,
- BackupManagerConstants constants) {
+ UserBackupManagerService userBackupManagerService) {
callingUid = Binder.getCallingUid();
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 92570aa..e0f9be4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -50,6 +50,7 @@
import android.annotation.NonNull;
import android.app.Activity;
import android.app.AppOpsManager;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.appwidget.AppWidgetManager;
import android.content.IIntentReceiver;
@@ -215,7 +216,7 @@
return new BroadcastRecord(mImpl, intent, mProcess, PACKAGE_RED, null, 21, 42, false, null,
null, null, null, AppOpsManager.OP_NONE, options, receivers, null, resultTo,
Activity.RESULT_OK, null, null, ordered, false, false, UserHandle.USER_SYSTEM,
- false, null, false, null);
+ BackgroundStartPrivileges.NONE, false, null);
}
private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 72d8556..5f4ff1a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -49,6 +49,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
import android.app.ReceiverInfo;
@@ -635,8 +636,8 @@
return new BroadcastRecord(mQueue, intent, callerApp, callerApp.info.packageName, null,
callerApp.getPid(), callerApp.info.uid, false, null, null, null, null,
AppOpsManager.OP_NONE, options, receivers, callerApp, resultTo,
- Activity.RESULT_OK, null, resultExtras, ordered, false, false, userId, false, null,
- false, null);
+ Activity.RESULT_OK, null, resultExtras, ordered, false, false, userId,
+ BackgroundStartPrivileges.NONE, false, null);
}
private static Map<String, Object> asMap(Bundle bundle) {
@@ -1707,20 +1708,21 @@
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
- final Binder backgroundActivityStartsToken = new Binder();
+ final BackgroundStartPrivileges backgroundStartPrivileges =
+ BackgroundStartPrivileges.allowBackgroundActivityStarts(new Binder());
final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord r = new BroadcastRecord(mQueue, intent, callerApp,
callerApp.info.packageName, null, callerApp.getPid(), callerApp.info.uid, false,
null, null, null, null, AppOpsManager.OP_NONE, BroadcastOptions.makeBasic(),
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), null, null,
- Activity.RESULT_OK, null, null, false, false, false, UserHandle.USER_SYSTEM, true,
- backgroundActivityStartsToken, false, null);
+ Activity.RESULT_OK, null, null, false, false, false, UserHandle.USER_SYSTEM,
+ backgroundStartPrivileges, false, null);
enqueueBroadcast(r);
waitForIdle();
- verify(receiverApp).addOrUpdateAllowBackgroundActivityStartsToken(eq(r),
- eq(backgroundActivityStartsToken));
- verify(receiverApp).removeAllowBackgroundActivityStartsToken(eq(r));
+ verify(receiverApp).addOrUpdateBackgroundStartPrivileges(eq(r),
+ eq(backgroundStartPrivileges));
+ verify(receiverApp).removeBackgroundStartPrivileges(eq(r));
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index 3864c88..01e2768 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -36,6 +36,7 @@
import static org.mockito.Mockito.doReturn;
import android.app.ActivityManagerInternal;
+import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.content.Intent;
import android.content.IntentFilter;
@@ -695,8 +696,7 @@
false /* sticky */,
false /* initialSticky */,
userId,
- false /* allowBackgroundActivityStarts */,
- null /* activityStartsToken */,
+ BackgroundStartPrivileges.NONE,
false /* timeoutExempt */,
filterExtrasForReceiver);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 1367af8..d03d196 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -20,25 +20,32 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.provider.Settings;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import androidx.test.annotation.UiThreadTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.server.ExtendedMockitoTestCase;
import com.android.server.LocalServices;
import com.android.server.am.UserState;
import com.android.server.pm.UserManagerService.UserData;
+import com.android.server.storage.DeviceStorageMonitorInternal;
import org.junit.After;
import org.junit.Before;
@@ -86,6 +93,10 @@
private @Mock PackageManagerService mMockPms;
private @Mock UserDataPreparer mMockUserDataPreparer;
private @Mock ActivityManagerInternal mActivityManagerInternal;
+ private @Mock DeviceStorageMonitorInternal mDeviceStorageMonitorInternal;
+ private @Mock StorageManager mStorageManager;
+ private @Mock LockSettingsInternal mLockSettingsInternal;
+ private @Mock PackageManagerInternal mPackageManagerInternal;
/**
* Reference to the {@link UserManagerService} being tested.
@@ -101,7 +112,8 @@
protected void initializeSession(StaticMockitoSessionBuilder builder) {
builder
.spyStatic(UserManager.class)
- .spyStatic(LocalServices.class);
+ .spyStatic(LocalServices.class)
+ .mockStatic(Settings.Global.class);
}
@Before
@@ -112,6 +124,14 @@
// Called when WatchedUserStates is constructed
doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+ // Called when creating new users
+ when(mDeviceStorageMonitorInternal.isMemoryLow()).thenReturn(false);
+ mockGetLocalService(DeviceStorageMonitorInternal.class, mDeviceStorageMonitorInternal);
+ when(mSpiedContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
+ mockGetLocalService(LockSettingsInternal.class, mLockSettingsInternal);
+ mockGetLocalService(PackageManagerInternal.class, mPackageManagerInternal);
+ doNothing().when(mSpiedContext).sendBroadcastAsUser(any(), any(), any());
+
// Must construct UserManagerService in the UiThread
mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
mPackagesLock, mRealContext.getDataDir(), mUsers);
@@ -135,6 +155,15 @@
}
@Test
+ public void testGetCurrentAndTargetUserIds() {
+ mockCurrentAndTargetUser(USER_ID, OTHER_USER_ID);
+
+ assertWithMessage("getCurrentAndTargetUserIds()")
+ .that(mUms.getCurrentAndTargetUserIds())
+ .isEqualTo(new Pair<>(USER_ID, OTHER_USER_ID));
+ }
+
+ @Test
public void testGetCurrentUserId() {
mockCurrentUser(USER_ID);
@@ -223,12 +252,101 @@
.that(mUms.isUserRunning(PROFILE_USER_ID)).isFalse();
}
+ @Test
+ public void testSetBootUser_SuppliedUserIsSwitchable() throws Exception {
+ addUser(USER_ID);
+ addUser(OTHER_USER_ID);
+
+ mUms.setBootUser(OTHER_USER_ID);
+
+ assertWithMessage("getBootUser")
+ .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
+ }
+
+ @Test
+ public void testSetBootUser_NotHeadless_SuppliedUserIsNotSwitchable() throws Exception {
+ setSystemUserHeadless(false);
+ addUser(USER_ID);
+ addUser(OTHER_USER_ID);
+ addDefaultProfileAndParent();
+
+ mUms.setBootUser(PROFILE_USER_ID);
+
+ assertWithMessage("getBootUser")
+ .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
+ }
+
+ @Test
+ public void testSetBootUser_Headless_SuppliedUserIsNotSwitchable() throws Exception {
+ setSystemUserHeadless(true);
+ addUser(USER_ID);
+ setLastForegroundTime(USER_ID, 1_000_000L);
+ addUser(OTHER_USER_ID);
+ setLastForegroundTime(OTHER_USER_ID, 2_000_000L);
+ addDefaultProfileAndParent();
+
+ mUms.setBootUser(PROFILE_USER_ID);
+
+ // Boot user not switchable so return most recently in foreground.
+ assertWithMessage("getBootUser")
+ .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
+ }
+
+ @Test
+ public void testGetBootUser_NotHeadless_ReturnsSystemUser() throws Exception {
+ setSystemUserHeadless(false);
+ addUser(USER_ID);
+ addUser(OTHER_USER_ID);
+
+ assertWithMessage("getBootUser")
+ .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
+ }
+
+ @Test
+ public void testGetBootUser_Headless_ReturnsMostRecentlyInForeground() throws Exception {
+ setSystemUserHeadless(true);
+ addUser(USER_ID);
+ setLastForegroundTime(USER_ID, 1_000_000L);
+
+ addUser(OTHER_USER_ID);
+ setLastForegroundTime(OTHER_USER_ID, 2_000_000L);
+
+ assertWithMessage("getBootUser")
+ .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
+ }
+
+ @Test
+ public void testGetBootUser_Headless_UserCreatedIfOnlySystemUserExists() throws Exception {
+ setSystemUserHeadless(true);
+
+ int bootUser = mUmi.getBootUser();
+
+ assertWithMessage("getStartingUser")
+ .that(bootUser).isNotEqualTo(UserHandle.USER_SYSTEM);
+
+ UserData newUser = mUsers.get(bootUser);
+ assertWithMessage("New boot user is a full user")
+ .that(newUser.info.isFull()).isTrue();
+ assertWithMessage("New boot user is an admin user")
+ .that(newUser.info.isAdmin()).isTrue();
+ assertWithMessage("New boot user is the main user")
+ .that(newUser.info.isMain()).isTrue();
+ }
+
private void mockCurrentUser(@UserIdInt int userId) {
mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
}
+ private void mockCurrentAndTargetUser(@UserIdInt int currentUserId,
+ @UserIdInt int targetUserId) {
+ mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+
+ when(mActivityManagerInternal.getCurrentAndTargetUserIds())
+ .thenReturn(new Pair<>(currentUserId, targetUserId));
+ }
+
private <T> void mockGetLocalService(Class<T> serviceClass, T service) {
doReturn(service).when(() -> LocalServices.getService(serviceClass));
}
@@ -248,7 +366,7 @@
private void addUser(@UserIdInt int userId) {
TestUserData userData = new TestUserData(userId);
-
+ userData.info.flags = UserInfo.FLAG_FULL;
addUserData(userData);
}
@@ -277,6 +395,23 @@
mUsers.put(userData.info.id, userData);
}
+ private void setSystemUserHeadless(boolean headless) {
+ UserData systemUser = mUsers.get(UserHandle.USER_SYSTEM);
+ if (headless) {
+ systemUser.info.flags &= ~UserInfo.FLAG_FULL;
+ systemUser.info.userType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
+ } else {
+ systemUser.info.flags |= UserInfo.FLAG_FULL;
+ systemUser.info.userType = UserManager.USER_TYPE_FULL_SYSTEM;
+ }
+ doReturn(headless).when(() -> UserManager.isHeadlessSystemUserMode());
+ }
+
+ private void setLastForegroundTime(@UserIdInt int userId, long timeMillis) {
+ UserData userData = mUsers.get(userId);
+ userData.mLastEnteredForegroundTimeMillis = timeMillis;
+ }
+
private static final class TestUserData extends UserData {
@SuppressWarnings("deprecation")
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 c08f6bf..a924207 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -306,12 +306,13 @@
verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent);
verifyCurrentSystemData(testUserId);
- spyOn(mService.mLastWallpaper.connection);
- doReturn(true).when(mService.mLastWallpaper.connection).isUsableDisplay(any());
+ spyOn(mService.mWallpaperDisplayHelper);
+ doReturn(true).when(mService.mWallpaperDisplayHelper)
+ .isUsableDisplay(any(Display.class), mService.mLastWallpaper.connection.mClientUid);
mService.mLastWallpaper.connection.attachEngine(mock(IWallpaperEngine.class),
DEFAULT_DISPLAY);
- WallpaperManagerService.WallpaperConnection.DisplayConnector connector =
+ WallpaperManagerService.DisplayConnector connector =
mService.mLastWallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY);
mService.setWallpaperComponent(sDefaultWallpaperComponent, FLAG_SYSTEM, testUserId);
@@ -521,7 +522,7 @@
}
private void verifyDisplayData() {
- mService.forEachDisplayData(data -> {
+ mService.mWallpaperDisplayHelper.forEachDisplayData(data -> {
assertTrue("Display width must larger than maximum screen size",
data.mWidth >= DISPLAY_SIZE_DIMENSION);
assertTrue("Display height must larger than maximum screen size",
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index e54a48b..1298e7b 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -1292,10 +1292,11 @@
unlockSystemUser();
try {
mAms.hasFeatures(
- null, // response
- AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
- new String[] {"feature1", "feature2"}, // features
- "testPackage"); // opPackageName
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ new String[] {"feature1", "feature2"}, // features
+ 0, // userId
+ "testPackage"); // opPackageName
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
// IllegalArgumentException is expected.
@@ -1307,10 +1308,11 @@
unlockSystemUser();
try {
mAms.hasFeatures(
- mMockAccountManagerResponse, // response
- null, // account
- new String[] {"feature1", "feature2"}, // features
- "testPackage"); // opPackageName
+ mMockAccountManagerResponse, // response
+ null, // account
+ new String[] {"feature1", "feature2"}, // features
+ 0, // userId
+ "testPackage"); // opPackageName
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
// IllegalArgumentException is expected.
@@ -1325,6 +1327,7 @@
mMockAccountManagerResponse, // response
AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, // account
null, // features
+ 0, // userId
"testPackage"); // opPackageName
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
@@ -1341,6 +1344,7 @@
response, // response
AccountManagerServiceTestFixtures.ACCOUNT_ERROR, // account
AccountManagerServiceTestFixtures.ACCOUNT_FEATURES, // features
+ 0, // userId
"testPackage"); // opPackageName
waitForLatch(latch);
verify(mMockAccountManagerResponse).onError(
@@ -1357,6 +1361,7 @@
response, // response
AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, // account
AccountManagerServiceTestFixtures.ACCOUNT_FEATURES, // features
+ 0, // userId
"testPackage"); // opPackageName
waitForLatch(latch);
verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index e6ab73a..162855a 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -119,12 +119,13 @@
final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
annotation);
mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
- parentShortComponentName, parentProcess, aboveSystem, timeoutRecord);
+ parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
+ /*isContinuousAnr*/ false);
verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mExecutorService),
- eq(false) /* onlyDumpSelf */);
+ eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/);
}
@Test
@@ -137,13 +138,14 @@
processingLatch.await();
return null;
}).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
- anyBoolean(), any(), any(), anyBoolean());
+ anyBoolean(), any(), any(), anyBoolean(), anyBoolean());
final ApplicationInfo appInfo = new ApplicationInfo();
final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
"annotation");
final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
"activityShortComponentName", appInfo, "parentShortComponentName",
- null /* parentProcess */, false /* aboveSystem */, timeoutRecord);
+ null /* parentProcess */, false /* aboveSystem */, timeoutRecord,
+ false /*isContinuousAnr*/);
reportAnr.run();
// This should be skipped because the pid is pending in queue.
reportAnr.run();
@@ -160,6 +162,6 @@
// There is only one ANR reported.
verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
anyString(), any(), any(), any(), anyBoolean(), any(), eq(mExecutorService),
- anyBoolean());
+ anyBoolean(), anyBoolean());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
index 9cada91..6350e22 100644
--- a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
@@ -202,6 +202,7 @@
TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchNoFocusedWindow(annotation);
processErrorState.appNotResponding(null /* activityShortComponentName */, null /* aInfo */,
null /* parentShortComponentName */, null /* parentProcess */,
- false /* aboveSystem */, timeoutRecord, mExecutorService, false /* onlyDumpSelf */);
+ false /* aboveSystem */, timeoutRecord, mExecutorService, false /* onlyDumpSelf */,
+ false /*isContinuousAnr*/);
}
}
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 eb99e30..00d4a6d 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
@@ -332,7 +332,7 @@
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
mAssociationInfo = new AssociationInfo(/* associationId= */ 1, 0, null,
- MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0);
+ MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0, -1);
mVdms = new VirtualDeviceManagerService(mContext);
mLocalService = mVdms.getLocalServiceInstance();
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
index d4e3d44..0dd60b8 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -95,7 +96,7 @@
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
doNothing().when(mAccountManagerInternal).addOnAppPermissionChangeListener(any());
when(mJobSchedulerInternal.getSystemScheduledPendingJobs()).thenReturn(new ArrayList<>());
- mSyncManager = new SyncManagerWithMockedServices(mContext, true);
+ mSyncManager = spy(new SyncManagerWithMockedServices(mContext, true));
}
public void testSyncExtrasEquals_WithNull() throws Exception {
@@ -233,6 +234,7 @@
}
public void testShouldDisableSync() {
+ doReturn(true).when(mSyncManager).isContactSharingAllowedForCloneProfile();
UserInfo primaryUserInfo = createUserInfo("primary", 0 /* id */, 0 /* groupId */,
UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
UserInfo cloneUserInfo = createUserInfo("clone", 10 /* id */, 0 /* groupId */,
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 61c3f13..210aeef 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -7396,7 +7396,7 @@
verify(getServices().alarmManager, times(1)).set(anyInt(), eq(PROFILE_OFF_DEADLINE), any());
// Now the user should see a warning notification.
verify(getServices().notificationManager, times(1))
- .notify(anyInt(), any());
+ .notifyAsUser(any(), anyInt(), any(), any());
// Apps shouldn't be suspended yet.
verifyZeroInteractions(getServices().ipackageManager);
clearInvocations(getServices().alarmManager);
@@ -7410,7 +7410,7 @@
verifyZeroInteractions(getServices().alarmManager);
// Now the user should see a notification about suspended apps.
verify(getServices().notificationManager, times(1))
- .notify(anyInt(), any());
+ .notifyAsUser(any(), anyInt(), any(), any());
// Verify that the apps are suspended.
verify(getServices().ipackageManager, times(1)).setPackagesSuspendedAsUser(
any(), eq(true), any(), any(), any(), any(), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
new file mode 100644
index 0000000..6c5a569
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.grammaticalinflection;
+
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.collect.Maps;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class GrammaticalInflectionBackupTest {
+ private static final int DEFAULT_USER_ID = 0;
+ private static final String DEFAULT_PACKAGE_NAME = "com.test.package.name";
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock
+ private GrammaticalInflectionService mGrammaticalInflectionService;
+
+ private GrammaticalInflectionBackupHelper mBackupHelper;
+
+ @Before
+ public void setUp() throws Exception {
+ mBackupHelper = new GrammaticalInflectionBackupHelper(
+ mGrammaticalInflectionService, mMockPackageManager);
+ }
+
+ @Test
+ public void testBackupPayload_noAppsInstalled_returnsNull() {
+ assertNull(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));
+ }
+
+ @Test
+ public void testBackupPayload_AppsInstalled_returnsGender()
+ throws IOException, ClassNotFoundException {
+ mockAppInstalled();
+ mockGetApplicationGrammaticalGender(Configuration.GRAMMATICAL_GENDER_MASCULINE);
+
+ HashMap<String, Integer> payload =
+ readFromByteArray(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));
+
+ // verify the payload
+ HashMap<String, Integer> expectationMap = new HashMap<>();
+ expectationMap.put(DEFAULT_PACKAGE_NAME, Configuration.GRAMMATICAL_GENDER_MASCULINE);
+ assertTrue(Maps.difference(payload, expectationMap).areEqual());
+ }
+
+ @Test
+ public void testApplyPayload_onPackageAdded_setApplicationGrammaticalGender()
+ throws IOException {
+ mockAppInstalled();
+
+ HashMap<String, Integer> testData = new HashMap<>();
+ testData.put(DEFAULT_PACKAGE_NAME, Configuration.GRAMMATICAL_GENDER_NEUTRAL);
+ mBackupHelper.stageAndApplyRestoredPayload(convertToByteArray(testData), DEFAULT_USER_ID);
+ mBackupHelper.onPackageAdded(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
+
+ verify(mGrammaticalInflectionService).setRequestedApplicationGrammaticalGender(
+ eq(DEFAULT_PACKAGE_NAME),
+ eq(DEFAULT_USER_ID),
+ eq(Configuration.GRAMMATICAL_GENDER_NEUTRAL));
+ }
+
+ private void mockAppInstalled() {
+ ApplicationInfo dummyApp = new ApplicationInfo();
+ dummyApp.packageName = DEFAULT_PACKAGE_NAME;
+ doReturn(List.of(dummyApp)).when(mMockPackageManager)
+ .getInstalledApplicationsAsUser(any(), anyInt());
+ }
+
+ private void mockGetApplicationGrammaticalGender(int grammaticalGender) {
+ doReturn(grammaticalGender).when(mGrammaticalInflectionService)
+ .getApplicationGrammaticalGender(
+ eq(DEFAULT_PACKAGE_NAME), eq(DEFAULT_USER_ID));
+ }
+
+ private byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) throws IOException{
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final ObjectOutputStream objStream = new ObjectOutputStream(out)) {
+ objStream.writeObject(pkgGenderInfo);
+ return out.toByteArray();
+ } catch (IOException e) {
+ throw e;
+ }
+ }
+
+ private HashMap<String, Integer> readFromByteArray(byte[] payload)
+ throws IOException, ClassNotFoundException {
+ HashMap<String, Integer> data;
+
+ try (ByteArrayInputStream byteIn = new ByteArrayInputStream(payload);
+ ObjectInputStream in = new ObjectInputStream(byteIn)) {
+ data = (HashMap<String, Integer>) in.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw e;
+ }
+ return data;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 304344e..fa8d866 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -687,6 +687,34 @@
}
@Test
+ public void testGetConversation_unsyncedShortcut() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID)).isNotNull();
+
+ when(mShortcutServiceInternal.getShortcuts(
+ anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+ anyInt(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(Collections.emptyList());
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+
+ // Conversation is removed from store as there is no matching shortcut in ShortcutManager
+ assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID)).isNull();
+ verify(mNotificationManagerInternal)
+ .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, Set.of(TEST_SHORTCUT_ID));
+ }
+
+ @Test
public void testOnNotificationChannelModified() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
index bbe8907..c9f00d7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
@@ -23,12 +23,12 @@
import android.app.ActivityManager;
import android.app.IStopUserCallback;
-import android.app.UserSwitchObserver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Postsubmit;
+import android.provider.Settings;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -37,10 +37,12 @@
import com.android.internal.util.FunctionalUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -56,18 +58,30 @@
private static final String TAG = "UserLifecycleStressTest";
// TODO: Make this smaller once we have improved it.
private static final int TIMEOUT_IN_SECOND = 40;
- private static final int NUM_ITERATIONS = 10;
+ private static final int NUM_ITERATIONS = 8;
private static final int WAIT_BEFORE_STOP_USER_IN_SECOND = 3;
private Context mContext;
private UserManager mUserManager;
private ActivityManager mActivityManager;
+ private UserSwitchWaiter mUserSwitchWaiter;
+ private String mRemoveGuestOnExitOriginalValue;
@Before
- public void setup() {
+ public void setup() throws RemoteException {
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mUserManager = mContext.getSystemService(UserManager.class);
mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mUserSwitchWaiter = new UserSwitchWaiter(TAG, TIMEOUT_IN_SECOND);
+ mRemoveGuestOnExitOriginalValue = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ mUserSwitchWaiter.close();
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, mRemoveGuestOnExitOriginalValue);
}
/**
@@ -101,10 +115,13 @@
* 1. While the guest user is in foreground, mark it for deletion.
* 2. Create a new guest. (This wouldn't be possible if the old one wasn't marked for deletion)
* 3. Switch to newly created guest.
- * 4. Remove the previous guest before waiting for switch to complete.
+ * 4. Remove the previous guest after the switch is complete.
**/
@Test
- public void switchToExistingGuestAndStartOverStressTest() throws Exception {
+ public void switchToExistingGuestAndStartOverStressTest() {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, "0");
+
if (ActivityManager.getCurrentUser() != USER_SYSTEM) {
switchUser(USER_SYSTEM);
}
@@ -135,14 +152,15 @@
.isNotNull();
Log.d(TAG, "Switching to the new guest");
- switchUserThenRun(newGuest.id, () -> {
- if (currentGuestId != USER_NULL) {
- Log.d(TAG, "Removing the previous guest before waiting for switch to complete");
- assertWithMessage("Couldn't remove guest")
- .that(mUserManager.removeUser(currentGuestId))
- .isTrue();
- }
- });
+ switchUser(newGuest.id);
+
+ if (currentGuestId != USER_NULL) {
+ Log.d(TAG, "Removing the previous guest");
+ assertWithMessage("Couldn't remove guest")
+ .that(mUserManager.removeUser(currentGuestId))
+ .isTrue();
+ }
+
Log.d(TAG, "Switching back to the system user");
switchUser(USER_SYSTEM);
@@ -174,33 +192,14 @@
}
/** Starts the given user in the foreground and waits for the switch to finish. */
- private void switchUser(int userId) throws RemoteException, InterruptedException {
- switchUserThenRun(userId, null);
- }
+ private void switchUser(int userId) {
+ Log.d(TAG, "Switching to user " + userId);
- /**
- * Starts the given user in the foreground. And runs the given Runnable right after
- * am.switchUser call, before waiting for the actual user switch to be complete.
- **/
- private void switchUserThenRun(int userId, Runnable runAfterSwitchBeforeWait)
- throws RemoteException, InterruptedException {
- runWithLatch("switch user", countDownLatch -> {
- ActivityManager.getService().registerUserSwitchObserver(
- new UserSwitchObserver() {
- @Override
- public void onUserSwitchComplete(int newUserId) {
- if (userId == newUserId) {
- countDownLatch.countDown();
- }
- }
- }, TAG);
- Log.d(TAG, "Switching to user " + userId);
- assertWithMessage("Failed to switch to user")
- .that(mActivityManager.switchUser(userId))
- .isTrue();
- if (runAfterSwitchBeforeWait != null) {
- runAfterSwitchBeforeWait.run();
- }
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> {
+ assertWithMessage("Could not start switching to user " + userId)
+ .that(mActivityManager.switchUser(userId)).isTrue();
+ }, /* onFail= */ () -> {
+ throw new AssertionError("Could not complete switching to user " + userId);
});
}
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 1889d9a..76a13f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -75,7 +75,7 @@
private static final int REMOVE_CHECK_INTERVAL_MILLIS = 500; // 0.5 seconds
private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds
- private static final int SWITCH_USER_TIMEOUT_MILLIS = 40 * 1000; // 40 seconds
+ private static final int SWITCH_USER_TIMEOUT_SECONDS = 40; // 40 seconds
// Packages which are used during tests.
private static final String[] PACKAGES = new String[] {
@@ -87,19 +87,21 @@
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private final Object mUserRemoveLock = new Object();
- private final Object mUserSwitchLock = new Object();
private UserManager mUserManager = null;
+ private ActivityManager mActivityManager;
private PackageManager mPackageManager;
private List<Integer> usersToRemove;
+ private UserSwitchWaiter mUserSwitchWaiter;
@Before
public void setUp() throws Exception {
mUserManager = UserManager.get(mContext);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
mPackageManager = mContext.getPackageManager();
+ mUserSwitchWaiter = new UserSwitchWaiter(TAG, SWITCH_USER_TIMEOUT_SECONDS);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -109,11 +111,6 @@
mUserRemoveLock.notifyAll();
}
break;
- case Intent.ACTION_USER_SWITCHED:
- synchronized (mUserSwitchLock) {
- mUserSwitchLock.notifyAll();
- }
- break;
}
}
}, filter);
@@ -124,6 +121,7 @@
@After
public void tearDown() throws Exception {
+ mUserSwitchWaiter.close();
for (Integer userId : usersToRemove) {
removeUser(userId);
}
@@ -322,6 +320,66 @@
@MediumTest
@Test
+ public void testRemoveUserShouldNotRemoveCurrentUser() {
+ final int startUser = ActivityManager.getCurrentUser();
+ final UserInfo testUser = createUser("TestUser", /* flags= */ 0);
+ // Switch to the user just created.
+ switchUser(testUser.id);
+
+ assertWithMessage("Current user should not be removed")
+ .that(mUserManager.removeUser(testUser.id))
+ .isFalse();
+
+ // Switch back to the starting user.
+ switchUser(startUser);
+
+ // Now we can remove the user
+ removeUser(testUser.id);
+ }
+
+ @MediumTest
+ @Test
+ public void testRemoveUserShouldNotRemoveCurrentUser_DuringUserSwitch() {
+ final int startUser = ActivityManager.getCurrentUser();
+ final UserInfo testUser = createUser("TestUser", /* flags= */ 0);
+ // Switch to the user just created.
+ switchUser(testUser.id);
+
+ switchUserThenRun(startUser, () -> {
+ // While the user switch is happening, call removeUser for the current user.
+ assertWithMessage("Current user should not be removed during user switch")
+ .that(mUserManager.removeUser(testUser.id))
+ .isFalse();
+ });
+ assertThat(hasUser(testUser.id)).isTrue();
+
+ // Now we can remove the user
+ removeUser(testUser.id);
+ }
+
+ @MediumTest
+ @Test
+ public void testRemoveUserShouldNotRemoveTargetUser_DuringUserSwitch() {
+ final int startUser = ActivityManager.getCurrentUser();
+ final UserInfo testUser = createUser("TestUser", /* flags= */ 0);
+
+ switchUserThenRun(testUser.id, () -> {
+ // While the user switch is happening, call removeUser for the target user.
+ assertWithMessage("Target user should not be removed during user switch")
+ .that(mUserManager.removeUser(testUser.id))
+ .isFalse();
+ });
+ assertThat(hasUser(testUser.id)).isTrue();
+
+ // Switch back to the starting user.
+ switchUser(startUser);
+
+ // Now we can remove the user
+ removeUser(testUser.id);
+ }
+
+ @MediumTest
+ @Test
public void testRemoveUserWhenPossible_restrictedReturnsError() throws Exception {
final int currentUser = ActivityManager.getCurrentUser();
final UserInfo user1 = createUser("User 1", /* flags= */ 0);
@@ -383,7 +441,7 @@
final UserInfo otherUser = createUser("User 1", /* flags= */ UserInfo.FLAG_ADMIN);
UserHandle mainUser = mUserManager.getMainUser();
- switchUser(otherUser.id, null, true);
+ switchUser(otherUser.id);
assertThat(mUserManager.removeUserWhenPossible(mainUser,
/* overrideDevicePolicy= */ false))
@@ -393,7 +451,7 @@
assertThat(hasUser(mainUser.getIdentifier())).isTrue();
// Switch back to the starting user.
- switchUser(currentUser, null, true);
+ switchUser(currentUser);
}
@MediumTest
@@ -411,7 +469,7 @@
final int startUser = ActivityManager.getCurrentUser();
final UserInfo user1 = createUser("User 1", /* flags= */ 0);
// Switch to the user just created.
- switchUser(user1.id, null, /* ignoreHandle= */ true);
+ switchUser(user1.id);
assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(),
/* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_DEFERRED);
@@ -420,7 +478,7 @@
assertThat(getUser(user1.id).isEphemeral()).isTrue();
// Switch back to the starting user.
- switchUser(startUser, null, /* ignoreHandle= */ true);
+ switchUser(startUser);
// User is removed once switch is complete
synchronized (mUserRemoveLock) {
@@ -431,6 +489,55 @@
@MediumTest
@Test
+ public void testRemoveUserWhenPossible_currentUserSetEphemeral_duringUserSwitch() {
+ final int startUser = ActivityManager.getCurrentUser();
+ final UserInfo testUser = createUser("TestUser", /* flags= */ 0);
+ // Switch to the user just created.
+ switchUser(testUser.id);
+
+ switchUserThenRun(startUser, () -> {
+ // While the user switch is happening, call removeUserWhenPossible for the current user.
+ assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false))
+ .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED);
+
+ assertThat(hasUser(testUser.id)).isTrue();
+ assertThat(getUser(testUser.id).isEphemeral()).isTrue();
+ });
+
+ // User is removed once switch is complete
+ synchronized (mUserRemoveLock) {
+ waitForUserRemovalLocked(testUser.id);
+ }
+ assertThat(hasUser(testUser.id)).isFalse();
+ }
+
+ @MediumTest
+ @Test
+ public void testRemoveUserWhenPossible_targetUserSetEphemeral_duringUserSwitch() {
+ final int startUser = ActivityManager.getCurrentUser();
+ final UserInfo testUser = createUser("TestUser", /* flags= */ 0);
+
+ switchUserThenRun(testUser.id, () -> {
+ // While the user switch is happening, call removeUserWhenPossible for the target user.
+ assertThat(mUserManager.removeUserWhenPossible(testUser.getUserHandle(), false))
+ .isEqualTo(UserManager.REMOVE_RESULT_DEFERRED);
+
+ assertThat(hasUser(testUser.id)).isTrue();
+ assertThat(getUser(testUser.id).isEphemeral()).isTrue();
+ });
+
+ // Switch back to the starting user.
+ switchUser(startUser);
+
+ // User is removed once switch is complete
+ synchronized (mUserRemoveLock) {
+ waitForUserRemovalLocked(testUser.id);
+ }
+ assertThat(hasUser(testUser.id)).isFalse();
+ }
+
+ @MediumTest
+ @Test
public void testRemoveUserWhenPossible_nonCurrentUserRemoved() throws Exception {
final UserInfo user1 = createUser("User 1", /* flags= */ 0);
synchronized (mUserRemoveLock) {
@@ -1149,33 +1256,30 @@
@LargeTest
@Test
public void testSwitchUser() {
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
- final int startUser = am.getCurrentUser();
+ final int startUser = ActivityManager.getCurrentUser();
UserInfo user = createUser("User", 0);
assertThat(user).isNotNull();
// Switch to the user just created.
- switchUser(user.id, null, true);
+ switchUser(user.id);
// Switch back to the starting user.
- switchUser(startUser, null, true);
+ switchUser(startUser);
}
@LargeTest
@Test
public void testSwitchUserByHandle() {
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
- final int startUser = am.getCurrentUser();
+ final int startUser = ActivityManager.getCurrentUser();
UserInfo user = createUser("User", 0);
assertThat(user).isNotNull();
// Switch to the user just created.
- switchUser(-1, user.getUserHandle(), false);
+ switchUser(user.getUserHandle());
// Switch back to the starting user.
- switchUser(-1, UserHandle.of(startUser), false);
+ switchUser(UserHandle.of(startUser));
}
@Test
public void testSwitchUserByHandle_ThrowsException() {
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
- assertThrows(IllegalArgumentException.class, () -> am.switchUser(null));
+ assertThrows(IllegalArgumentException.class, () -> mActivityManager.switchUser(null));
}
@MediumTest
@@ -1319,31 +1423,43 @@
}
/**
- * @param userId value will be used to call switchUser(int) only if ignoreHandle is false.
- * @param user value will be used to call switchUser(UserHandle) only if ignoreHandle is true.
- * @param ignoreHandle if true, switchUser(int) will be called with the provided userId,
- * else, switchUser(UserHandle) will be called with the provided user.
- */
- private void switchUser(int userId, UserHandle user, boolean ignoreHandle) {
- synchronized (mUserSwitchLock) {
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
- if (ignoreHandle) {
- am.switchUser(userId);
- } else {
- am.switchUser(user);
+ * Starts the given user in the foreground. And waits for the user switch to be complete.
+ **/
+ private void switchUser(UserHandle user) {
+ final int userId = user.getIdentifier();
+ Slog.d(TAG, "Switching to user " + userId);
+
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> {
+ assertWithMessage("Could not start switching to user " + userId)
+ .that(mActivityManager.switchUser(user)).isTrue();
+ }, /* onFail= */ () -> {
+ throw new AssertionError("Could not complete switching to user " + userId);
+ });
+ }
+
+ /**
+ * Starts the given user in the foreground. And waits for the user switch to be complete.
+ **/
+ private void switchUser(int userId) {
+ switchUserThenRun(userId, null);
+ }
+
+ /**
+ * Starts the given user in the foreground. And runs the given Runnable right after
+ * am.switchUser call, before waiting for the actual user switch to be complete.
+ **/
+ private void switchUserThenRun(int userId, Runnable runAfterSwitchBeforeWait) {
+ Slog.d(TAG, "Switching to user " + userId);
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> {
+ // Start switching to user
+ assertWithMessage("Could not start switching to user " + userId)
+ .that(mActivityManager.switchUser(userId)).isTrue();
+
+ // While the user switch is happening, call runAfterSwitchBeforeWait.
+ if (runAfterSwitchBeforeWait != null) {
+ runAfterSwitchBeforeWait.run();
}
- long time = System.currentTimeMillis();
- try {
- mUserSwitchLock.wait(SWITCH_USER_TIMEOUT_MILLIS);
- } catch (InterruptedException ie) {
- Thread.currentThread().interrupt();
- return;
- }
- if (System.currentTimeMillis() - time > SWITCH_USER_TIMEOUT_MILLIS) {
- fail("Timeout waiting for the user switch to u"
- + (ignoreHandle ? userId : user.getIdentifier()));
- }
- }
+ }, () -> fail("Could not complete switching to user " + userId));
}
private void removeUser(UserHandle user) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSwitchWaiter.java b/services/tests/servicestests/src/com/android/server/pm/UserSwitchWaiter.java
new file mode 100644
index 0000000..d948570
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSwitchWaiter.java
@@ -0,0 +1,108 @@
+/*
+ * 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.pm;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.IUserSwitchObserver;
+import android.app.UserSwitchObserver;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.FunctionalUtils;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class UserSwitchWaiter implements Closeable {
+
+ private final String mTag;
+ private final int mTimeoutInSecond;
+ private final IActivityManager mActivityManager;
+ private final IUserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
+ @Override
+ public void onUserSwitchComplete(int newUserId) {
+ getSemaphoreSwitchComplete(newUserId).release();
+ }
+
+ @Override
+ public void onLockedBootComplete(int newUserId) {
+ getSemaphoreBootComplete(newUserId).release();
+ }
+ };
+
+ private final Map<Integer, Semaphore> mSemaphoresMapSwitchComplete = new ConcurrentHashMap<>();
+ private Semaphore getSemaphoreSwitchComplete(final int userId) {
+ return mSemaphoresMapSwitchComplete.computeIfAbsent(userId,
+ (Integer absentKey) -> new Semaphore(0));
+ }
+
+ private final Map<Integer, Semaphore> mSemaphoresMapBootComplete = new ConcurrentHashMap<>();
+ private Semaphore getSemaphoreBootComplete(final int userId) {
+ return mSemaphoresMapBootComplete.computeIfAbsent(userId,
+ (Integer absentKey) -> new Semaphore(0));
+ }
+
+ public UserSwitchWaiter(String tag, int timeoutInSecond) throws RemoteException {
+ mTag = tag;
+ mTimeoutInSecond = timeoutInSecond;
+ mActivityManager = ActivityManager.getService();
+
+ mActivityManager.registerUserSwitchObserver(mUserSwitchObserver, mTag);
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ mActivityManager.unregisterUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Failed to unregister user switch observer", e);
+ }
+ }
+
+ public void runThenWaitUntilSwitchCompleted(int userId,
+ FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) {
+ final Semaphore semaphore = getSemaphoreSwitchComplete(userId);
+ semaphore.drainPermits();
+ runnable.run();
+ waitForSemaphore(semaphore, onFail);
+ }
+
+ public void runThenWaitUntilBootCompleted(int userId,
+ FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) {
+ final Semaphore semaphore = getSemaphoreBootComplete(userId);
+ semaphore.drainPermits();
+ runnable.run();
+ waitForSemaphore(semaphore, onFail);
+ }
+
+ private void waitForSemaphore(Semaphore semaphore, Runnable onFail) {
+ boolean success = false;
+ try {
+ success = semaphore.tryAcquire(mTimeoutInSecond, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Log.e(mTag, "Thread interrupted unexpectedly.", e);
+ }
+ if (!success && onFail != null) {
+ onFail.run();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java b/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
index d059472..2e647c4 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
@@ -602,6 +602,8 @@
stats.noteNetworkInterfaceForTransports("cellular",
new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+ stats.notePhoneOnLocked(9800, 9800);
+
// Note application network activity
NetworkStats networkStats = new NetworkStats(10000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
@@ -614,27 +616,34 @@
mStatsRule.setTime(12_000, 12_000);
- MobileRadioPowerCalculator calculator =
+ MobileRadioPowerCalculator mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
- mStatsRule.apply(calculator);
+ PhonePowerCalculator phonePowerCalculator =
+ new PhonePowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+ // 1800ms data duration / 2000 total duration * 2.77778 mAh = 2.5
+ // 200ms phone on duration / 2000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.77778);
+ .isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+ assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isWithin(PRECISION).of(0.27778);
+ assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(1.53934);
+ .isWithin(PRECISION).of(1.38541);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(1.53934);
+ .isWithin(PRECISION).of(1.38541);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
@@ -649,6 +658,9 @@
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+ stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
+ 0, 0);
+
// Scan for a cell
stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
TelephonyManager.SIM_STATE_READY,
@@ -686,6 +698,9 @@
stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
+
+ stats.notePhoneOnLocked(9000, 9000);
+
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
@@ -732,16 +747,24 @@
mStatsRule.setTime(10_000, 10_000);
- MobileRadioPowerCalculator calculator =
+ MobileRadioPowerCalculator mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
- mStatsRule.apply(calculator);
+ PhonePowerCalculator phonePowerCalculator =
+ new PhonePowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
+ // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+ // 9000ms data duration / 10000 total duration * 2.77778 mAh = 2.5
+ // 1000ms phone on duration / 10000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.77778);
+ .isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+ assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isWithin(PRECISION).of(0.27778);
+ assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
// CDMA2000 [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// [720, 1080, 1440, 1800, 2160, 1440] mA . [10, 11, 12, 13, 14, 15] ms = 111600 mA-ms
@@ -767,10 +790,10 @@
// _________________
// = 5177753 mA-ms estimated total consumption
//
- // 2.77778 mA-h measured total consumption * 3957753 / 5177753 = 2.123268 mA-h
+ // 2.5 mA-h measured total consumption * 3957753 / 5177753 = 1.91094 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.123268);
+ .isWithin(PRECISION).of(1.91094);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
@@ -791,17 +814,17 @@
// 3333768 * 133.33333 / 204.44444 = 2174196.52174 mA-ms App 1 Tx Power Consumption
//
// Total App Power consumption * Ratio of App 1 / Total Estimated Power Consumption
- // 2.123268 * (467988.75 + 2174196.52174) / 3957753 = 1.41749 App 1 Power Consumption
+ // 1.91094 * (467988.75 + 2174196.52174) / 3957753 = 1.27574 App 1 Power Consumption
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(1.41749);
+ .isWithin(PRECISION).of(1.27574);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
// Rest should go to the other app
UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(0.705778);
+ .isWithin(PRECISION).of(0.63520);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
@@ -814,6 +837,9 @@
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+ stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
+ 0, 0);
+
// Scan for a cell
stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
TelephonyManager.SIM_STATE_READY,
@@ -851,6 +877,9 @@
stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
+
+ stats.notePhoneOnLocked(9000, 9000);
+
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GREAT);
@@ -868,30 +897,38 @@
mStatsRule.setTime(12_000, 12_000);
- MobileRadioPowerCalculator calculator =
- new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
- mStatsRule.apply(calculator);
+ MobileRadioPowerCalculator mobileRadioPowerCalculator =
+ new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
+ PhonePowerCalculator phonePowerCalculator =
+ new PhonePowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+ // 9000ms data duration / 10000 total duration * 2.77778 mAh = 2.5
+ // 1000ms phone on duration / 10000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.77778);
+ .isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+ assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isWithin(PRECISION).of(0.27778);
+ assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
// Estimated Rx/Tx modem consumption = 0.94 mAh
// Estimated total modem consumption = 1.27888 mAh
- // 2.77778 * 0.94 / 1.27888 = 2.04170 mAh
+ // 2.5 * 0.94 / 1.27888 = 1.83754 mAh
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.04170);
+ .isWithin(PRECISION).of(1.83754);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(2.04170);
+ .isWithin(PRECISION).of(1.83754);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index b8cb149..963b27e 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -25,11 +25,13 @@
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
+import android.media.tv.tuner.filter.Filter;
import android.media.tv.tuner.frontend.FrontendSettings;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
+import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
@@ -806,20 +808,137 @@
@Test
public void requestDemuxTest() {
// Register client
- ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
+ ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
+ ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ int[] clientId0 = new int[1];
mTunerResourceManagerService.registerClientProfileInternal(
- profile, null /*listener*/, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ profile0, null /*listener*/, clientId0);
+ assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- int[] demuxHandle = new int[1];
- TunerDemuxRequest request = new TunerDemuxRequest();
- request.clientId = clientId[0];
- assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle))
+ TunerDemuxInfo[] infos = new TunerDemuxInfo[3];
+ infos[0] = tunerDemuxInfo(0 /* handle */, Filter.TYPE_TS | Filter.TYPE_IP);
+ infos[1] = tunerDemuxInfo(1 /* handle */, Filter.TYPE_TLV);
+ infos[2] = tunerDemuxInfo(2 /* handle */, Filter.TYPE_TS);
+ mTunerResourceManagerService.setDemuxInfoListInternal(infos);
+
+ int[] demuxHandle0 = new int[1];
+ // first with undefined type (should be the first one with least # of caps)
+ TunerDemuxRequest request = tunerDemuxRequest(clientId0[0], Filter.TYPE_UNDEFINED);
+ assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
.isTrue();
- assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle[0]))
+ assertThat(demuxHandle0[0]).isEqualTo(1);
+ DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
+ mTunerResourceManagerService.releaseDemuxInternal(dr);
+
+ // now with non-supported type (ALP)
+ request.desiredFilterTypes = Filter.TYPE_ALP;
+ demuxHandle0[0] = -1;
+ assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
+ .isFalse();
+ assertThat(demuxHandle0[0]).isEqualTo(-1);
+
+ // now with TS (should be the one with least # of caps that supports TS)
+ request.desiredFilterTypes = Filter.TYPE_TS;
+ assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
+ .isTrue();
+ assertThat(demuxHandle0[0]).isEqualTo(2);
+
+ // request for another TS
+ int[] clientId1 = new int[1];
+ mTunerResourceManagerService.registerClientProfileInternal(
+ profile1, null /*listener*/, clientId1);
+ assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ int[] demuxHandle1 = new int[1];
+ TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_TS);
+ assertThat(mTunerResourceManagerService.requestDemuxInternal(request1, demuxHandle1))
+ .isTrue();
+ assertThat(demuxHandle1[0]).isEqualTo(0);
+ assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle1[0]))
.isEqualTo(0);
+
+ // release demuxes
+ dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
+ mTunerResourceManagerService.releaseDemuxInternal(dr);
+ dr = mTunerResourceManagerService.getDemuxResource(demuxHandle1[0]);
+ mTunerResourceManagerService.releaseDemuxInternal(dr);
+ }
+
+ @Test
+ public void requestDemuxTest_ResourceReclaim() {
+ // Register clients
+ ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
+ ResourceClientProfile profile2 = resourceClientProfile("2" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
+ int[] clientId0 = new int[1];
+ int[] clientId1 = new int[1];
+ int[] clientId2 = new int[1];
+ TestResourcesReclaimListener listener0 = new TestResourcesReclaimListener();
+ TestResourcesReclaimListener listener1 = new TestResourcesReclaimListener();
+ TestResourcesReclaimListener listener2 = new TestResourcesReclaimListener();
+
+ mTunerResourceManagerService.registerClientProfileInternal(
+ profile0, listener0, clientId0);
+ assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ mTunerResourceManagerService.registerClientProfileInternal(
+ profile1, listener1, clientId1);
+ assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ mTunerResourceManagerService.registerClientProfileInternal(
+ profile2, listener2, clientId1);
+ assertThat(clientId2[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+
+ // Init demux resources.
+ TunerDemuxInfo[] infos = new TunerDemuxInfo[2];
+ infos[0] = tunerDemuxInfo(0 /*handle*/, Filter.TYPE_TS | Filter.TYPE_IP);
+ infos[1] = tunerDemuxInfo(1 /*handle*/, Filter.TYPE_TS);
+ mTunerResourceManagerService.setDemuxInfoListInternal(infos);
+
+ // let clientId0(prio:100) request for IP - should succeed
+ TunerDemuxRequest request0 = tunerDemuxRequest(clientId0[0], Filter.TYPE_IP);
+ int[] demuxHandle0 = new int[1];
+ assertThat(mTunerResourceManagerService
+ .requestDemuxInternal(request0, demuxHandle0)).isTrue();
+ assertThat(demuxHandle0[0]).isEqualTo(0);
+
+ // let clientId1(prio:50) request for IP - should fail
+ TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_IP);
+ int[] demuxHandle1 = new int[1];
+ demuxHandle1[0] = -1;
+ assertThat(mTunerResourceManagerService
+ .requestDemuxInternal(request1, demuxHandle1)).isFalse();
+ assertThat(listener0.isReclaimed()).isFalse();
+ assertThat(demuxHandle1[0]).isEqualTo(-1);
+
+ // let clientId1(prio:50) request for TS - should succeed
+ request1.desiredFilterTypes = Filter.TYPE_TS;
+ assertThat(mTunerResourceManagerService
+ .requestDemuxInternal(request1, demuxHandle1)).isTrue();
+ assertThat(demuxHandle1[0]).isEqualTo(1);
+ assertThat(listener0.isReclaimed()).isFalse();
+
+ // now release demux for the clientId0 (higher priority) and request demux
+ DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
+ mTunerResourceManagerService.releaseDemuxInternal(dr);
+
+ // let clientId2(prio:50) request for TS - should succeed
+ TunerDemuxRequest request2 = tunerDemuxRequest(clientId2[0], Filter.TYPE_TS);
+ int[] demuxHandle2 = new int[1];
+ assertThat(mTunerResourceManagerService
+ .requestDemuxInternal(request2, demuxHandle2)).isTrue();
+ assertThat(demuxHandle2[0]).isEqualTo(0);
+ assertThat(listener1.isReclaimed()).isFalse();
+
+ // let clientId0(prio:100) request for TS - should reclaim from clientId2
+ // , who has the smaller caps
+ request0.desiredFilterTypes = Filter.TYPE_TS;
+ assertThat(mTunerResourceManagerService
+ .requestDemuxInternal(request0, demuxHandle0)).isTrue();
+ assertThat(listener1.isReclaimed()).isFalse();
+ assertThat(listener2.isReclaimed()).isTrue();
}
@Test
@@ -1188,4 +1307,18 @@
request.ciCamId = ciCamId;
return request;
}
+
+ private TunerDemuxInfo tunerDemuxInfo(int handle, int supportedFilterTypes) {
+ TunerDemuxInfo info = new TunerDemuxInfo();
+ info.handle = handle;
+ info.filterTypes = supportedFilterTypes;
+ return info;
+ }
+
+ private TunerDemuxRequest tunerDemuxRequest(int clientId, int desiredFilterTypes) {
+ TunerDemuxRequest request = new TunerDemuxRequest();
+ request.clientId = clientId;
+ request.desiredFilterTypes = desiredFilterTypes;
+ return request;
+ }
}
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
new file mode 100644
index 0000000..9ca2876
--- /dev/null
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -0,0 +1,60 @@
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FrameworksVoiceInteractionTests",
+ defaults: [
+ "modules-utils-testable-device-config-defaults",
+ ],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.runner",
+ "androidx.test.ext.truth",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ "services.voiceinteraction",
+ "servicestests-core-utils",
+ "servicestests-utils-mockito-extended",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/voiceinteractiontests/AndroidManifest.xml b/services/tests/voiceinteractiontests/AndroidManifest.xml
new file mode 100644
index 0000000..ce76a51
--- /dev/null
+++ b/services/tests/voiceinteractiontests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.voiceinteractiontests">
+
+ <application android:testOnly="true"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.voiceinteractiontests"
+ android:label="Frameworks Voice Interaction Services Tests" />
+
+</manifest>
diff --git a/services/tests/voiceinteractiontests/AndroidTest.xml b/services/tests/voiceinteractiontests/AndroidTest.xml
new file mode 100644
index 0000000..ce48633
--- /dev/null
+++ b/services/tests/voiceinteractiontests/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<configuration description="Runs Frameworks Voice Interaction Services Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="FrameworksVoiceInteractionTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="FrameworksVoiceInteractionTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.voiceinteractiontests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/services/tests/voiceinteractiontests/OWNERS b/services/tests/voiceinteractiontests/OWNERS
new file mode 100644
index 0000000..86d392e
--- /dev/null
+++ b/services/tests/voiceinteractiontests/OWNERS
@@ -0,0 +1 @@
+include /services/voiceinteraction/OWNERS
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/HotwordAudioStreamCopierTest.java b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/HotwordAudioStreamCopierTest.java
new file mode 100644
index 0000000..8f35c11
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/HotwordAudioStreamCopierTest.java
@@ -0,0 +1,296 @@
+/*
+ * 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.voiceinteraction;
+
+import static android.service.voice.HotwordAudioStream.KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES;
+
+import static com.android.server.voiceinteraction.HotwordAudioStreamCopier.DEFAULT_COPY_BUFFER_LENGTH_BYTES;
+import static com.android.server.voiceinteraction.HotwordAudioStreamCopier.MAX_COPY_BUFFER_LENGTH_BYTES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.AppOpsManager;
+import android.media.AudioFormat;
+import android.media.MediaSyncEvent;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.Presubmit;
+import android.service.voice.HotwordAudioStream;
+import android.service.voice.HotwordDetectedResult;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class HotwordAudioStreamCopierTest {
+
+ private static final int DETECTOR_TYPE = 1;
+ private static final int VOICE_INTERACTOR_UID = 999;
+ private static final String VOICE_INTERACTOR_PACKAGE_NAME = "VIPackageName";
+ private static final String VOICE_INTERACTOR_ATTRIBUTION_TAG = "VIAttributionTag";
+ private static final AudioFormat FAKE_AUDIO_FORMAT =
+ new AudioFormat.Builder()
+ .setSampleRate(32000)
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setChannelMask(AudioFormat.CHANNEL_IN_MONO).build();
+
+ private HotwordAudioStreamCopier mCopier;
+ private AppOpsManager mAppOpsManager;
+
+ @Before
+ public void setUp() {
+ mAppOpsManager = mock(AppOpsManager.class);
+ mCopier = new HotwordAudioStreamCopier(mAppOpsManager, DETECTOR_TYPE, VOICE_INTERACTOR_UID,
+ VOICE_INTERACTOR_PACKAGE_NAME, VOICE_INTERACTOR_ATTRIBUTION_TAG);
+ }
+
+ @Test
+ public void testDefaultCopyBufferLength() throws Exception {
+ ParcelFileDescriptor[] fakeAudioStreamPipe = ParcelFileDescriptor.createPipe();
+ try {
+ // There is no copy buffer length is specified in the metadata.
+ // HotwordAudioStreamCopier should use the default copy buffer length.
+ List<HotwordAudioStream> originalAudioStreams = new ArrayList<>();
+ HotwordAudioStream audioStream = new HotwordAudioStream.Builder(FAKE_AUDIO_FORMAT,
+ fakeAudioStreamPipe[0]).build();
+ originalAudioStreams.add(audioStream);
+ HotwordDetectedResult originalResult = buildHotwordDetectedResultWithStreams(
+ originalAudioStreams);
+
+ HotwordDetectedResult managedResult = mCopier.startCopyingAudioStreams(
+ originalResult);
+ List<HotwordAudioStream> managedAudioStreams = managedResult.getAudioStreams();
+ assertThat(managedAudioStreams.size()).isEqualTo(1);
+
+ ParcelFileDescriptor readFd =
+ managedAudioStreams.get(0).getAudioStreamParcelFileDescriptor();
+ ParcelFileDescriptor writeFd = fakeAudioStreamPipe[1];
+ verifyCopyBufferLength(DEFAULT_COPY_BUFFER_LENGTH_BYTES, readFd, writeFd);
+ } finally {
+ closeAudioStreamPipe(fakeAudioStreamPipe);
+ }
+ }
+
+ @Test
+ public void testCustomCopyBufferLength() throws Exception {
+ List<ParcelFileDescriptor[]> fakeAudioStreamPipes = new ArrayList<>();
+ try {
+ // We create 4 audio streams, with various small prime values specified in the metadata.
+ // HotwordAudioStreamCopier reads data in chunks the size of the buffer. In
+ // verifyCopyBufferLength(), we check if the number of bytes read from the copied stream
+ // is a multiple of the buffer length.
+ //
+ // By using prime numbers, this ensures that HotwordAudioStreamCopier is reading the
+ // correct buffer length for the corresponding stream, since multiples of different
+ // primes cannot be equal. A small number helps ensure that the test reads the copied
+ // stream before HotwordAudioStreamCopier can copy the entire source stream (which has
+ // a large size).
+ int[] copyBufferLengths = new int[]{2, 3, 5, 7};
+ List<HotwordAudioStream> originalAudioStreams = new ArrayList<>();
+ for (int i = 0; i < copyBufferLengths.length; i++) {
+ ParcelFileDescriptor[] fakeAudioStreamPipe = ParcelFileDescriptor.createPipe();
+ fakeAudioStreamPipes.add(fakeAudioStreamPipe);
+ HotwordAudioStream audioStream = new HotwordAudioStream.Builder(FAKE_AUDIO_FORMAT,
+ fakeAudioStreamPipe[0]).build();
+ audioStream.getMetadata().putInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES,
+ copyBufferLengths[i]);
+ originalAudioStreams.add(audioStream);
+ }
+ HotwordDetectedResult originalResult = buildHotwordDetectedResultWithStreams(
+ originalAudioStreams);
+
+ HotwordDetectedResult managedResult = mCopier.startCopyingAudioStreams(
+ originalResult);
+ List<HotwordAudioStream> managedAudioStreams = managedResult.getAudioStreams();
+ assertThat(managedAudioStreams.size()).isEqualTo(copyBufferLengths.length);
+
+ for (int i = 0; i < copyBufferLengths.length; i++) {
+ ParcelFileDescriptor readFd =
+ managedAudioStreams.get(i).getAudioStreamParcelFileDescriptor();
+ ParcelFileDescriptor writeFd = fakeAudioStreamPipes.get(i)[1];
+ verifyCopyBufferLength(copyBufferLengths[i], readFd, writeFd);
+ }
+ } finally {
+ for (ParcelFileDescriptor[] fakeAudioStreamPipe : fakeAudioStreamPipes) {
+ closeAudioStreamPipe(fakeAudioStreamPipe);
+ }
+ }
+ }
+
+ @Test
+ public void testInvalidCopyBufferLength_NonPositive() throws Exception {
+ ParcelFileDescriptor[] fakeAudioStreamPipe = ParcelFileDescriptor.createPipe();
+ try {
+ // An invalid copy buffer length (non-positive) is specified in the metadata.
+ // HotwordAudioStreamCopier should use the default copy buffer length.
+ List<HotwordAudioStream> originalAudioStreams = new ArrayList<>();
+ HotwordAudioStream audioStream = new HotwordAudioStream.Builder(FAKE_AUDIO_FORMAT,
+ fakeAudioStreamPipe[0]).build();
+ audioStream.getMetadata().putInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, 0);
+ originalAudioStreams.add(audioStream);
+ HotwordDetectedResult originalResult = buildHotwordDetectedResultWithStreams(
+ originalAudioStreams);
+
+ HotwordDetectedResult managedResult = mCopier.startCopyingAudioStreams(
+ originalResult);
+ List<HotwordAudioStream> managedAudioStreams = managedResult.getAudioStreams();
+ assertThat(managedAudioStreams.size()).isEqualTo(1);
+
+ ParcelFileDescriptor readFd =
+ managedAudioStreams.get(0).getAudioStreamParcelFileDescriptor();
+ ParcelFileDescriptor writeFd = fakeAudioStreamPipe[1];
+ verifyCopyBufferLength(DEFAULT_COPY_BUFFER_LENGTH_BYTES, readFd, writeFd);
+ } finally {
+ closeAudioStreamPipe(fakeAudioStreamPipe);
+ }
+ }
+
+ @Test
+ public void testInvalidCopyBufferLength_ExceedsMaximum() throws Exception {
+ ParcelFileDescriptor[] fakeAudioStreamPipe = ParcelFileDescriptor.createPipe();
+ try {
+ // An invalid copy buffer length (exceeds the maximum) is specified in the metadata.
+ // HotwordAudioStreamCopier should use the default copy buffer length.
+ List<HotwordAudioStream> originalAudioStreams = new ArrayList<>();
+ HotwordAudioStream audioStream = new HotwordAudioStream.Builder(FAKE_AUDIO_FORMAT,
+ fakeAudioStreamPipe[0]).build();
+ audioStream.getMetadata().putInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES,
+ MAX_COPY_BUFFER_LENGTH_BYTES + 1);
+ originalAudioStreams.add(audioStream);
+ HotwordDetectedResult originalResult = buildHotwordDetectedResultWithStreams(
+ originalAudioStreams);
+
+ HotwordDetectedResult managedResult = mCopier.startCopyingAudioStreams(
+ originalResult);
+ List<HotwordAudioStream> managedAudioStreams = managedResult.getAudioStreams();
+ assertThat(managedAudioStreams.size()).isEqualTo(1);
+
+ ParcelFileDescriptor readFd =
+ managedAudioStreams.get(0).getAudioStreamParcelFileDescriptor();
+ ParcelFileDescriptor writeFd = fakeAudioStreamPipe[1];
+ verifyCopyBufferLength(DEFAULT_COPY_BUFFER_LENGTH_BYTES, readFd, writeFd);
+ } finally {
+ closeAudioStreamPipe(fakeAudioStreamPipe);
+ }
+ }
+
+ @Test
+ public void testInvalidCopyBufferLength_NotAnInt() throws Exception {
+ ParcelFileDescriptor[] fakeAudioStreamPipe = ParcelFileDescriptor.createPipe();
+ try {
+ // An invalid copy buffer length (not an int) is specified in the metadata.
+ // HotwordAudioStreamCopier should use the default copy buffer length.
+ List<HotwordAudioStream> originalAudioStreams = new ArrayList<>();
+ HotwordAudioStream audioStream = new HotwordAudioStream.Builder(FAKE_AUDIO_FORMAT,
+ fakeAudioStreamPipe[0]).build();
+ audioStream.getMetadata().putString(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES,
+ "Not an int");
+ originalAudioStreams.add(audioStream);
+ HotwordDetectedResult originalResult = buildHotwordDetectedResultWithStreams(
+ originalAudioStreams);
+
+ HotwordDetectedResult managedResult = mCopier.startCopyingAudioStreams(
+ originalResult);
+ List<HotwordAudioStream> managedAudioStreams = managedResult.getAudioStreams();
+ assertThat(managedAudioStreams.size()).isEqualTo(1);
+
+ ParcelFileDescriptor readFd =
+ managedAudioStreams.get(0).getAudioStreamParcelFileDescriptor();
+ ParcelFileDescriptor writeFd = fakeAudioStreamPipe[1];
+ verifyCopyBufferLength(DEFAULT_COPY_BUFFER_LENGTH_BYTES, readFd, writeFd);
+ } finally {
+ closeAudioStreamPipe(fakeAudioStreamPipe);
+ }
+ }
+
+ private void verifyCopyBufferLength(int expectedCopyBufferLength, ParcelFileDescriptor readFd,
+ ParcelFileDescriptor writeFd) throws IOException {
+ byte[] bytesToRepeat = new byte[]{99};
+ try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(readFd);
+ OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd)) {
+ writeToFakeAudioStreamPipe(os, bytesToRepeat, MAX_COPY_BUFFER_LENGTH_BYTES);
+ byte[] actualBytesRead = new byte[MAX_COPY_BUFFER_LENGTH_BYTES];
+ int numBytesRead = is.read(actualBytesRead);
+
+ // HotwordAudioStreamCopier reads data in chunks the size of the buffer. We write MAX
+ // bytes but the actual number of bytes read from the copied stream should be a
+ // multiple of the buffer length.
+ assertThat(numBytesRead % expectedCopyBufferLength).isEqualTo(0);
+ }
+ }
+
+ @NotNull
+ private static HotwordDetectedResult buildHotwordDetectedResultWithStreams(
+ List<HotwordAudioStream> audioStreams) {
+ return new HotwordDetectedResult.Builder()
+ .setConfidenceLevel(HotwordDetectedResult.CONFIDENCE_LEVEL_LOW)
+ .setMediaSyncEvent(MediaSyncEvent.createEvent(
+ MediaSyncEvent.SYNC_EVENT_PRESENTATION_COMPLETE))
+ .setHotwordOffsetMillis(100)
+ .setHotwordDurationMillis(1000)
+ .setAudioChannel(1)
+ .setHotwordDetectionPersonalized(true)
+ .setScore(100)
+ .setPersonalizedScore(100)
+ .setHotwordPhraseId(1)
+ .setAudioStreams(audioStreams)
+ .setExtras(new PersistableBundle())
+ .build();
+ }
+
+ private static void writeToFakeAudioStreamPipe(OutputStream writeOutputStream,
+ byte[] bytesToRepeat, int totalBytesToWrite) throws IOException {
+ // Create the fake stream buffer, consisting of bytesToRepeat, repeated as many times as
+ // needed to get to totalBytesToWrite.
+ byte[] fakeAudioData = new byte[totalBytesToWrite];
+ int bytesWritten = 0;
+ while (bytesWritten + bytesToRepeat.length <= totalBytesToWrite) {
+ System.arraycopy(bytesToRepeat, 0, fakeAudioData, bytesWritten, bytesToRepeat.length);
+ bytesWritten += bytesToRepeat.length;
+ }
+ if (bytesWritten < totalBytesToWrite) {
+ int bytesLeft = totalBytesToWrite - bytesWritten;
+ System.arraycopy(bytesToRepeat, 0, fakeAudioData, bytesWritten, bytesLeft);
+ }
+
+ writeOutputStream.write(fakeAudioData);
+ }
+
+ private static void closeAudioStreamPipe(ParcelFileDescriptor[] parcelFileDescriptors)
+ throws IOException {
+ if (parcelFileDescriptors != null) {
+ parcelFileDescriptors[0].close();
+ parcelFileDescriptors[1].close();
+ }
+ }
+
+}
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 8f110a88..ca28558 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -81,6 +81,7 @@
import static org.mockito.ArgumentMatchers.notNull;
import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
@@ -886,7 +887,8 @@
doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
// caller is temp allowed
if (callerIsTempAllowed) {
- callerApp.addOrUpdateAllowBackgroundActivityStartsToken(new Binder(), null);
+ callerApp.addOrUpdateBackgroundStartPrivileges(new Binder(),
+ BackgroundStartPrivileges.ALLOW_BAL);
}
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 4ad8516..8cc362c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -280,7 +280,7 @@
}
@Test
- public void testStartRecording_notifiesCallback() {
+ public void testStartRecording_notifiesCallback_taskSession() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
@@ -292,6 +292,18 @@
}
@Test
+ public void testStartRecording_notifiesCallback_displaySession() {
+ // WHEN a recording is ongoing.
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ // THEN the visibility change callback is notified.
+ verify(mMediaProjectionManagerWrapper)
+ .notifyActiveProjectionCapturedContentVisibilityChanged(true);
+ }
+
+ @Test
public void testOnVisibleRequestedChanged_notifiesCallback() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index bc23fa3..78707d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2066,7 +2066,8 @@
// Update the forced size and density in settings and the unique id to simualate a display
// remap.
dc.mWmService.mDisplayWindowSettings.setForcedSize(dc, forcedWidth, forcedHeight);
- dc.mWmService.mDisplayWindowSettings.setForcedDensity(dc, forcedDensity, 0 /* userId */);
+ dc.mWmService.mDisplayWindowSettings.setForcedDensity(displayInfo, forcedDensity,
+ 0 /* userId */);
dc.mCurrentUniqueDisplayId = mDisplayInfo.uniqueId + "-test";
// Trigger display changed.
dc.onDisplayChanged();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index c398a0a..fb4f2ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -236,8 +236,8 @@
@Test
public void testSetForcedDensity() {
- mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay, 600 /* density */,
- 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay.getDisplayInfo(),
+ 600 /* density */, 0 /* userId */);
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
@@ -439,8 +439,9 @@
public void testDisplayWindowSettingsAppliedOnDisplayReady() {
// Set forced densities for two displays in DisplayWindowSettings
final DisplayContent dc = createMockSimulatedDisplay();
- mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
- mDisplayWindowSettings.setForcedDensity(dc, 456, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay.getDisplayInfo(), 123,
+ 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(dc.getDisplayInfo(), 456, 0 /* userId */);
// Apply settings to displays - the settings will be stored, but config will not be
// recalculated immediately.
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 bf1d1fa..d31ae6a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -203,6 +203,7 @@
}
final int displayId = SystemServicesTestRule.sNextDisplayId++;
+ mInfo.displayId = displayId;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay = createInternal(display);
diff --git a/services/voiceinteraction/TEST_MAPPING b/services/voiceinteraction/TEST_MAPPING
index af67637..d6c6964 100644
--- a/services/voiceinteraction/TEST_MAPPING
+++ b/services/voiceinteraction/TEST_MAPPING
@@ -31,6 +31,14 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "FrameworksVoiceInteractionTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
index ad84f00..cb5b930 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
@@ -71,6 +71,8 @@
@GuardedBy("mLock")
private boolean mValidatingDspTrigger = false;
+ @GuardedBy("mLock")
+ private HotwordRejectedResult mLastHotwordRejectedResult = null;
DspTrustedHotwordDetectorSession(
@NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService,
@@ -110,7 +112,8 @@
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED,
mVoiceInteractionServiceUid);
if (!mValidatingDspTrigger) {
- Slog.i(TAG, "Ignoring #onDetected due to a process restart");
+ Slog.i(TAG, "Ignoring #onDetected due to a process restart or previous"
+ + " #onRejected result = " + mLastHotwordRejectedResult);
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP,
METRICS_KEYPHRASE_TRIGGERED_DETECT_UNEXPECTED_CALLBACK,
@@ -173,6 +176,7 @@
}
mValidatingDspTrigger = false;
externalCallback.onRejected(result);
+ mLastHotwordRejectedResult = result;
if (mDebugHotwordLogging && result != null) {
Slog.i(TAG, "Egressed rejected result: " + result);
}
@@ -181,6 +185,7 @@
};
mValidatingDspTrigger = true;
+ mLastHotwordRejectedResult = null;
mRemoteDetectionService.run(service -> {
// We use the VALIDATION_TIMEOUT_MILLIS to inform that the client needs to invoke
// the callback before timeout value. In order to reduce the latency impact between
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
index 2bddd74..2413072 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -36,6 +36,8 @@
import android.service.voice.HotwordDetectedResult;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -60,10 +62,12 @@
private static final String OP_MESSAGE = "Streaming hotword audio to VoiceInteractionService";
private static final String TASK_ID_PREFIX = "HotwordDetectedResult@";
private static final String THREAD_NAME_PREFIX = "Copy-";
+ @VisibleForTesting
+ static final int DEFAULT_COPY_BUFFER_LENGTH_BYTES = 32_768;
// Corresponds to the OS pipe capacity in bytes
- private static final int MAX_COPY_BUFFER_LENGTH_BYTES = 65_536;
- private static final int DEFAULT_COPY_BUFFER_LENGTH_BYTES = 32_768;
+ @VisibleForTesting
+ static final int MAX_COPY_BUFFER_LENGTH_BYTES = 65_536;
private final AppOpsManager mAppOpsManager;
private final int mDetectorType;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index c373305..665d5e7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -635,6 +635,7 @@
return;
}
}
+ //TODO(b265535257): report error to either service only.
synchronized (HotwordDetectionConnection.this.mLock) {
runForEachDetectorSessionLocked((session) -> {
session.reportErrorLocked(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 19aa374..38bf9c2 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -331,6 +331,12 @@
@GuardedBy("this")
private boolean mTemporarilyDisabled;
+ /** The start value of showSessionId */
+ private static final int SHOW_SESSION_START_ID = 0;
+
+ @GuardedBy("this")
+ private int mShowSessionId = SHOW_SESSION_START_ID;
+
private final boolean mEnableService;
// TODO(b/226201975): remove reference once RoleService supports pre-created users
private final RoleObserver mRoleObserver;
@@ -350,6 +356,24 @@
}
}
+ int getNextShowSessionId() {
+ synchronized (this) {
+ // Reset the showSessionId to SHOW_SESSION_START_ID to avoid the value exceeds
+ // Integer.MAX_VALUE
+ if (mShowSessionId == Integer.MAX_VALUE - 1) {
+ mShowSessionId = SHOW_SESSION_START_ID;
+ }
+ mShowSessionId++;
+ return mShowSessionId;
+ }
+ }
+
+ int getShowSessionId() {
+ synchronized (this) {
+ return mShowSessionId;
+ }
+ }
+
@Override
public @NonNull IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator(
@NonNull Identity originatorIdentity, IBinder client) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 4ee3306..04c8f8f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -21,6 +21,7 @@
import static android.app.ActivityManager.START_VOICE_HIDDEN_SESSION;
import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.service.voice.VoiceInteractionService.KEY_SHOW_SESSION_ID;
import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
@@ -255,13 +256,17 @@
/* direct= */ true);
}
- public boolean showSessionLocked(@NonNull Bundle args, int flags,
+ public boolean showSessionLocked(@Nullable Bundle args, int flags,
@Nullable String attributionTag,
@Nullable IVoiceInteractionSessionShowCallback showCallback,
@Nullable IBinder activityToken) {
+ final int sessionId = mServiceStub.getNextShowSessionId();
+ final Bundle newArgs = args == null ? new Bundle() : args;
+ newArgs.putInt(KEY_SHOW_SESSION_ID, sessionId);
+
try {
if (mService != null) {
- mService.prepareToShowSession(args, flags);
+ mService.prepareToShowSession(newArgs, flags);
}
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException while calling prepareToShowSession", e);
@@ -275,7 +280,9 @@
if (!mActiveSession.mBound) {
try {
if (mService != null) {
- mService.showSessionFailed();
+ Bundle failedArgs = new Bundle();
+ failedArgs.putInt(KEY_SHOW_SESSION_ID, sessionId);
+ mService.showSessionFailed(failedArgs);
}
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException while calling showSessionFailed", e);
@@ -300,7 +307,7 @@
} else {
visibleActivities = allVisibleActivities;
}
- return mActiveSession.showLocked(args, flags, attributionTag, mDisabledShowContext,
+ return mActiveSession.showLocked(newArgs, flags, attributionTag, mDisabledShowContext,
showCallback, visibleActivities);
}
@@ -673,6 +680,21 @@
Slog.w(TAG, "Visual query detection service not in isolated process");
throw new IllegalStateException("Visual query detection not in isolated process");
}
+ if (!Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(
+ visualQueryDetectionServiceInfo.permission)) {
+ Slog.w(TAG, "Visual query detection does not require permission "
+ + Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE);
+ throw new SecurityException("Visual query detection does not require permission "
+ + Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE);
+ }
+ if (mContext.getPackageManager().checkPermission(
+ Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE,
+ mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Voice interaction service should not hold permission "
+ + Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE);
+ throw new SecurityException("Voice interaction service should not hold permission "
+ + Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE);
+ }
if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
Slog.w(TAG, "Can't set sharedMemory to be read-only");
throw new IllegalStateException("Can't set sharedMemory to be read-only");
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index 775f1b8..0dcf1b6 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -25,6 +25,14 @@
]
},
{
+ "name": "CtsTelephonyTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
"name": "CtsTelephony2TestCases",
"options": [
{
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 92d1e5b..b55a29c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -7066,7 +7066,7 @@
* Retry SMS over IMS after this Timer expires
*/
public static final String KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT =
- KEY_PREFIX + "sms_rover_ims_send_retry_delay_millis_int";
+ KEY_PREFIX + "sms_over_ims_send_retry_delay_millis_int";
/**
* TR1 Timer Value in milliseconds,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 913ea9a..31c844c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3217,17 +3217,17 @@
case NETWORK_TYPE_CDMA:
return "CDMA";
case NETWORK_TYPE_EVDO_0:
- return "CDMA - EvDo rev. 0";
+ return "EVDO-0";
case NETWORK_TYPE_EVDO_A:
- return "CDMA - EvDo rev. A";
+ return "EVDO-A";
case NETWORK_TYPE_EVDO_B:
- return "CDMA - EvDo rev. B";
+ return "EVDO-B";
case NETWORK_TYPE_1xRTT:
- return "CDMA - 1xRTT";
+ return "1xRTT";
case NETWORK_TYPE_LTE:
return "LTE";
case NETWORK_TYPE_EHRPD:
- return "CDMA - eHRPD";
+ return "eHRPD";
case NETWORK_TYPE_IDEN:
return "iDEN";
case NETWORK_TYPE_HSPAP:
@@ -3235,7 +3235,7 @@
case NETWORK_TYPE_GSM:
return "GSM";
case NETWORK_TYPE_TD_SCDMA:
- return "TD_SCDMA";
+ return "TD-SCDMA";
case NETWORK_TYPE_IWLAN:
return "IWLAN";
case NETWORK_TYPE_LTE_CA:
@@ -9549,10 +9549,10 @@
*/
public static boolean isValidAllowedNetworkTypesReason(@AllowedNetworkTypesReason int reason) {
switch (reason) {
- case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER:
- case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER:
- case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER:
- case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
+ case ALLOWED_NETWORK_TYPES_REASON_USER:
+ case ALLOWED_NETWORK_TYPES_REASON_POWER:
+ case ALLOWED_NETWORK_TYPES_REASON_CARRIER:
+ case ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
case ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS:
return true;
}
@@ -18009,4 +18009,45 @@
return "UNKNOWN(" + state + ")";
}
}
+
+ /**
+ * Convert the allowed network types reason to string.
+ *
+ * @param reason The allowed network types reason.
+ * @return The converted string.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String allowedNetworkTypesReasonToString(@AllowedNetworkTypesReason int reason) {
+ switch (reason) {
+ case ALLOWED_NETWORK_TYPES_REASON_USER: return "user";
+ case ALLOWED_NETWORK_TYPES_REASON_POWER: return "power";
+ case ALLOWED_NETWORK_TYPES_REASON_CARRIER: return "carrier";
+ case ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: return "enable_2g";
+ case ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS: return "user_restrictions";
+ default: return "unknown(" + reason + ")";
+ }
+ }
+
+ /**
+ * Convert the allowed network types reason from string.
+ *
+ * @param reason The reason in string format.
+ * @return The allowed network types reason.
+ *
+ * @hide
+ */
+ @AllowedNetworkTypesReason
+ public static int allowedNetworkTypesReasonFromString(@NonNull String reason) {
+ switch (reason) {
+ case "user": return ALLOWED_NETWORK_TYPES_REASON_USER;
+ case "power": return ALLOWED_NETWORK_TYPES_REASON_POWER;
+ case "carrier": return ALLOWED_NETWORK_TYPES_REASON_CARRIER;
+ case "enable_2g": return ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G;
+ case "user_restrictions": return ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS;
+ default: throw new IllegalArgumentException("allowedNetworkTypesReasonFromString: "
+ + "invalid reason " + reason);
+ }
+ }
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 84781b4..707b522 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -22,6 +22,10 @@
<!-- Ensure output directory is empty at the start -->
<option name="run-command" value="rm -rf /sdcard/flicker" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="FlickerTests.apk"/>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index c735be0..522f9e7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -48,7 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeAutoOpenWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTestCfArm.kt
new file mode 100644
index 0000000..70443d8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseImeAutoOpenWindowToAppTestCfArm(flicker: FlickerTest) :
+ CloseImeAutoOpenWindowToAppTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 4024f56..2081424 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -48,7 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeAutoOpenWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTestCfArm.kt
new file mode 100644
index 0000000..2ffc757
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class CloseImeAutoOpenWindowToHomeTestCfArm(flicker: FlickerTest) :
+ CloseImeAutoOpenWindowToHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 098c082..13feeb1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -43,7 +43,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTestCfArm.kt
new file mode 100644
index 0000000..f40f5e6
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTestCfArm.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseImeWindowToAppTestCfArm(flicker: FlickerTest) : CloseImeWindowToAppTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index f110e54..840575a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -41,7 +41,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTestCfArm.kt
new file mode 100644
index 0000000..87d9abd
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTestCfArm.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseImeWindowToHomeTestCfArm(flicker: FlickerTest) : CloseImeWindowToHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index 4891901..6685cf7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -72,7 +72,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class LaunchAppShowImeOnStartTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class LaunchAppShowImeOnStartTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
private val initializeApp = ImeStateInitializeHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTestCfArm.kt
new file mode 100644
index 0000000..04cae53
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class LaunchAppShowImeOnStartTestCfArm(flicker: FlickerTest) :
+ LaunchAppShowImeOnStartTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
index 33e9574..7d1f6cb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
@@ -46,7 +46,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowAndCloseTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class OpenImeWindowAndCloseTest(flicker: FlickerTest) : BaseTest(flicker) {
private val simpleApp = SimpleAppHelper(instrumentation)
private val testApp = ImeAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTestCfArm.kt
new file mode 100644
index 0000000..c40dfae
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class OpenImeWindowAndCloseTestCfArm(flicker: FlickerTest) :
+ OpenImeWindowAndCloseTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index 0e732b5..d41843f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -45,7 +45,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowFromFixedOrientationAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class OpenImeWindowFromFixedOrientationAppTest(flicker: FlickerTest) : BaseTest(flicker) {
private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTestCfArm.kt
new file mode 100644
index 0000000..0e6cb53
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenImeWindowFromFixedOrientationAppTestCfArm(flicker: FlickerTest) :
+ OpenImeWindowFromFixedOrientationAppTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index c097511..5b830e5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -37,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class OpenImeWindowTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTestCfArm.kt
new file mode 100644
index 0000000..34bd455
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTestCfArm.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenImeWindowTestCfArm(flicker: FlickerTest) : OpenImeWindowTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
index b05beba..d95af9d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -46,7 +46,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowToOverViewTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class OpenImeWindowToOverViewTest(flicker: FlickerTest) : BaseTest(flicker) {
private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTestCfArm.kt
new file mode 100644
index 0000000..8e6d7dc
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTestCfArm.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.wm.flicker.ime
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenImeWindowToOverViewTestCfArm(flicker: FlickerTest) : OpenImeWindowToOverViewTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTestCfArm.kt
new file mode 100644
index 0000000..1d3658e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTestCfArm.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.server.wm.flicker.ime
+
+import android.platform.test.annotations.Presubmit
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Presubmit
+open class SwitchImeWindowsFromGestureNavTestCfArm(flicker: FlickerTest) :
+ SwitchImeWindowsFromGestureNavTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 3d1342c..1baff37 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -74,11 +73,6 @@
}
}
- /** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
/**
* Checks that the [ActivityOptions.LaunchNewActivity] activity is visible at the start of the
* transition, that [ActivityOptions.SimpleActivity] becomes visible during the transition, and
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
index 4ca9d5fa..baa2750 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
@@ -21,10 +21,7 @@
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
import com.android.server.wm.flicker.helpers.CameraAppHelper
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -42,11 +39,6 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class OpenAppAfterCameraTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
private val cameraApp = CameraAppHelper(instrumentation)
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt
deleted file mode 100644
index a9f9204..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt
+++ /dev/null
@@ -1,162 +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.server.wm.flicker.launch
-
-import android.platform.test.annotations.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerTest
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launching an app after cold opening camera (with shell transitions)
- *
- * To run this test: `atest FlickerTests:OpenAppAfterCameraTest_ShellTransit`
- *
- * Notes: Some default assertions are inherited [OpenAppTransition]
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppAfterCameraTest_ShellTransit(flicker: FlickerTest) : OpenAppAfterCameraTest(flicker) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-
- @FlakyTest
- @Test
- override fun appLayerReplacesLauncher() {
- super.appLayerReplacesLauncher()
- }
-
- @FlakyTest
- @Test
- override fun appLayerBecomesVisible() {
- super.appLayerBecomesVisible()
- }
-
- @FlakyTest
- @Test
- override fun appWindowBecomesTopWindow() {
- super.appWindowBecomesTopWindow()
- }
-
- @FlakyTest
- @Test
- override fun appWindowBecomesVisible() {
- super.appWindowBecomesVisible()
- }
-
- @FlakyTest
- @Test
- override fun appWindowIsTopWindowAtEnd() {
- super.appWindowIsTopWindowAtEnd()
- }
-
- @FlakyTest
- @Test
- override fun appWindowReplacesLauncherAsTopWindow() {
- super.appWindowReplacesLauncherAsTopWindow()
- }
-
- @FlakyTest
- @Test
- override fun entireScreenCovered() {
- super.entireScreenCovered()
- }
-
- @FlakyTest
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() {
- super.navBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest
- @Test
- override fun navBarLayerPositionAtStartAndEnd() {
- super.navBarLayerPositionAtStartAndEnd()
- }
-
- @FlakyTest
- @Test
- override fun navBarWindowIsAlwaysVisible() {
- super.navBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() {
- super.statusBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() {
- super.statusBarLayerPositionAtStartAndEnd()
- }
-
- @FlakyTest
- @Test
- override fun statusBarWindowIsAlwaysVisible() {
- super.statusBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() {
- super.taskBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest
- @Test
- override fun taskBarWindowIsAlwaysVisible() {
- super.taskBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest
- @Test
- override fun focusChanges() {
- super.focusChanges()
- }
-
- @FlakyTest
- @Test
- override fun appWindowAsTopWindowAtEnd() {
- super.appWindowAsTopWindowAtEnd()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index 242f457..9d86f8c8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
@@ -25,7 +24,6 @@
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
import com.android.server.wm.traces.common.service.PlatformConsts
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -77,103 +75,6 @@
teardown { testApp.exit(wmHelper) }
}
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appWindowAsTopWindowAtEnd() = super.appWindowAsTopWindowAtEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appWindowReplacesLauncherAsTopWindow() =
- super.appWindowReplacesLauncherAsTopWindow()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appLayerBecomesVisible() = super.appLayerBecomesVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun entireScreenCovered() = super.entireScreenCovered()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028) @Test override fun focusChanges() = super.focusChanges()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 240916028)
- @Test
- override fun appWindowIsTopWindowAtEnd() = super.appWindowIsTopWindowAtEnd()
-
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index a4f09c0..9fbec97 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
@@ -71,11 +70,6 @@
}
/** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
@Presubmit @Test override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 56d7d5e..991cd1c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -113,9 +113,6 @@
override fun navBarWindowIsAlwaysVisible() {}
/** {@inheritDoc} */
- @Postsubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
-
- /** {@inheritDoc} */
@Postsubmit
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index 6c833c4..90c18c4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -61,9 +61,9 @@
}
}
- @Postsubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
+ @Presubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
- @Postsubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
+ @Presubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
/** {@inheritDoc} */
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index d582931..efca6ab 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.WindowInsets
@@ -112,9 +111,9 @@
teardown { testApp.exit(wmHelper) }
}
- @FlakyTest @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_warmStart()
+ @Presubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_warmStart()
- @Postsubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_warmStart()
+ @Presubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_warmStart()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index db4baa0..2b16ef0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -87,9 +87,6 @@
}
/** {@inheritDoc} */
- @Presubmit @Test override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
-
- /** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 7a7990f..93bf099 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -79,9 +79,6 @@
override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
/** {@inheritDoc} */
- @Presubmit @Test override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
-
- /** {@inheritDoc} */
@Presubmit
@Test
override fun appLayerBecomesVisible() = super.appLayerBecomesVisible_warmStart()
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
new file mode 100644
index 0000000..41316d8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
@@ -0,0 +1,156 @@
+/*
+ * 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.wm.flicker.launch
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.KeyEvent
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
+import com.android.server.wm.flicker.helpers.CameraAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launching camera from launcher by double pressing power button
+ *
+ * To run this test: `atest FlickerTests:OpenCameraOnDoubleClickPowerButton`
+ *
+ * Actions:
+ * ```
+ * Make sure no apps are running on the device
+ * Launch an app [testApp] and wait animation to complete
+ * ```
+ * Notes:
+ * ```
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ * ```
+ */
+@RequiresDevice
+@FlickerServiceCompatible
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
+ private val cameraApp = CameraAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ RemoveAllTasksButHomeRule.removeAllTasksButHome()
+ this.setRotation(flicker.scenario.startRotation)
+ }
+ transitions {
+ device.pressKeyCode(KeyEvent.KEYCODE_POWER)
+ device.pressKeyCode(KeyEvent.KEYCODE_POWER)
+ wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(cameraApp).waitForAndVerify()
+ }
+ teardown { RemoveAllTasksButHomeRule.removeAllTasksButHome() }
+ }
+
+ @Postsubmit @Test override fun appLayerBecomesVisible() = super.appLayerBecomesVisible()
+
+ @Postsubmit @Test override fun appWindowAsTopWindowAtEnd() = super.appWindowAsTopWindowAtEnd()
+
+ @Postsubmit @Test override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
+
+ @Postsubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
+
+ @Postsubmit @Test override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+ @Postsubmit @Test override fun appWindowIsTopWindowAtEnd() = super.appWindowIsTopWindowAtEnd()
+
+ @Postsubmit
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() =
+ super.appWindowReplacesLauncherAsTopWindow()
+
+ @Postsubmit @Test override fun focusChanges() = super.focusChanges()
+
+ @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
+
+ @Postsubmit
+ @Test
+ override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
+
+ @Postsubmit
+ @Test
+ override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
+
+ @Postsubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerIsVisibleAtStartAndEnd() =
+ super.statusBarLayerIsVisibleAtStartAndEnd()
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
+
+ @Postsubmit
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
+
+ @Postsubmit
+ @Test
+ override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Postsubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 31babb8..959ab3d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -20,7 +20,6 @@
import android.app.WallpaperManager
import android.content.res.Resources
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -92,7 +91,7 @@
* Checks that the [wallpaper] layer is never visible when performing task transitions. A solid
* color background should be shown instead.
*/
- @FlakyTest(bugId = 253617416)
+ @Presubmit
@Test
fun wallpaperLayerIsNeverVisible() {
flicker.assertLayers {
@@ -192,7 +191,7 @@
* Checks that we start with the LaunchNewTask activity on top and then open up the
* SimpleActivity and then go back to the LaunchNewTask activity.
*/
- @Postsubmit
+ @Presubmit
@Test
fun newTaskOpensOnTopAndThenCloses() {
flicker.assertWm {
@@ -208,11 +207,6 @@
}
}
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
companion object {
private fun getWallpaperPackage(instrumentation: Instrumentation): IComponentMatcher {
val wallpaperManager = WallpaperManager.getInstance(instrumentation.targetContext)
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index f2234fb..21007ef 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -74,6 +74,7 @@
],
test_suites: ["general-tests"],
test_config: "MultiUserRollbackTest.xml",
+ data : [":RollbackTest"],
}
java_library_host {