Merge "Remove host activity association when removing EmbeddedWindow" into udc-qpr-dev
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
index 47e1dad..4d41dcd 100644
--- a/cmds/uinput/README.md
+++ b/cmds/uinput/README.md
@@ -153,6 +153,38 @@
}
```
+4. `sync`
+
+A command used to get a response once the command is processed. When several `inject` and `delay`
+commands are used in a row, the `sync` command can be used to track the progress of the command
+queue.
+
+| Field | Type | Description |
+|:-----------:|:-------:|:---------------------------------------------|
+| `id` | integer | Device ID |
+| `command` | string | Must be set to "sync" |
+| `syncToken` | string | The token used to identify this sync command |
+
+Example:
+
+```json5
+{
+ "id": 1,
+ "command": "syncToken",
+ "syncToken": "finished_injecting_events"
+}
+```
+
+This command will result in the following response when it is processed:
+
+```json5
+{
+ "id": 1,
+ "result": "sync",
+ "syncToken": "finished_injecting_events"
+}
+```
+
### Notes
1. As soon as EOF is reached (either in interactive mode, or in file mode),
the device that was created will be unregistered. There is no
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index 732b33d..2f362d7 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -45,6 +45,7 @@
private static final int MSG_OPEN_UINPUT_DEVICE = 1;
private static final int MSG_CLOSE_UINPUT_DEVICE = 2;
private static final int MSG_INJECT_EVENT = 3;
+ private static final int MSG_SYNC_EVENT = 4;
private final int mId;
private final HandlerThread mThread;
@@ -119,6 +120,16 @@
}
/**
+ * Synchronize the uinput command queue by writing a sync response with the provided syncToken
+ * to the output stream when this event is processed.
+ *
+ * @param syncToken The token for this sync command.
+ */
+ public void syncEvent(String syncToken) {
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_SYNC_EVENT, syncToken), mTimeToSend);
+ }
+
+ /**
* Close an uinput device.
*
*/
@@ -171,6 +182,9 @@
mCond.notify();
}
break;
+ case MSG_SYNC_EVENT:
+ handleSyncEvent((String) msg.obj);
+ break;
default:
throw new IllegalArgumentException("Unknown device message");
}
@@ -184,6 +198,18 @@
getLooper().myQueue().removeSyncBarrier(mBarrierToken);
mBarrierToken = 0;
}
+
+ private void handleSyncEvent(String syncToken) {
+ final JSONObject json = new JSONObject();
+ try {
+ json.put("reason", "sync");
+ json.put("id", mId);
+ json.put("syncToken", syncToken);
+ } catch (JSONException e) {
+ throw new RuntimeException("Could not create JSON object ", e);
+ }
+ writeOutputObject(json);
+ }
}
private class DeviceCallback {
@@ -211,7 +237,7 @@
}
public void onDeviceVibrating(int value) {
- JSONObject json = new JSONObject();
+ final JSONObject json = new JSONObject();
try {
json.put("reason", "vibrating");
json.put("id", mId);
@@ -219,12 +245,7 @@
} catch (JSONException e) {
throw new RuntimeException("Could not create JSON object ", e);
}
- try {
- mOutputStream.write(json.toString().getBytes());
- mOutputStream.flush();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ writeOutputObject(json);
}
public void onDeviceError() {
@@ -234,4 +255,13 @@
msg.sendToTarget();
}
}
+
+ private void writeOutputObject(JSONObject json) {
+ try {
+ mOutputStream.write(json.toString().getBytes());
+ mOutputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index 4b090f5..91b4a74 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -25,6 +25,7 @@
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
import java.util.stream.IntStream;
import src.com.android.commands.uinput.InputAbsInfo;
@@ -36,11 +37,21 @@
public class Event {
private static final String TAG = "UinputEvent";
- public static final String COMMAND_REGISTER = "register";
- public static final String COMMAND_DELAY = "delay";
- public static final String COMMAND_INJECT = "inject";
private static final int ABS_CNT = 64;
+ enum Command {
+ REGISTER("register"),
+ DELAY("delay"),
+ INJECT("inject"),
+ SYNC("sync");
+
+ final String mCommandName;
+
+ Command(String command) {
+ mCommandName = command;
+ }
+ }
+
// These constants come from "include/uapi/linux/input.h" in the kernel
enum Bus {
USB(0x03), BLUETOOTH(0x05);
@@ -56,7 +67,7 @@
}
private int mId;
- private String mCommand;
+ private Command mCommand;
private String mName;
private int mVid;
private int mPid;
@@ -67,12 +78,13 @@
private int mFfEffectsMax = 0;
private String mInputport;
private SparseArray<InputAbsInfo> mAbsInfo;
+ private String mSyncToken;
public int getId() {
return mId;
}
- public String getCommand() {
+ public Command getCommand() {
return mCommand;
}
@@ -116,6 +128,10 @@
return mInputport;
}
+ public String getSyncToken() {
+ return mSyncToken;
+ }
+
/**
* Convert an event to String.
*/
@@ -146,7 +162,14 @@
}
private void setCommand(String command) {
- mEvent.mCommand = command;
+ Objects.requireNonNull(command, "Command must not be null");
+ for (Command cmd : Command.values()) {
+ if (cmd.mCommandName.equals(command)) {
+ mEvent.mCommand = cmd;
+ return;
+ }
+ }
+ throw new IllegalStateException("Unrecognized command: " + command);
}
public void setName(String name) {
@@ -189,27 +212,38 @@
mEvent.mInputport = port;
}
+ public void setSyncToken(String syncToken) {
+ mEvent.mSyncToken = Objects.requireNonNull(syncToken, "Sync token must not be null");
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
} else if (mEvent.mCommand == null) {
throw new IllegalStateException("Event does not contain a command");
}
- if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
- if (mEvent.mConfiguration == null) {
- throw new IllegalStateException(
- "Device registration is missing configuration");
+ switch (mEvent.mCommand) {
+ case REGISTER -> {
+ if (mEvent.mConfiguration == null) {
+ throw new IllegalStateException(
+ "Device registration is missing configuration");
+ }
}
- } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
- if (mEvent.mDuration <= 0) {
- throw new IllegalStateException("Delay has missing or invalid duration");
+ case DELAY -> {
+ if (mEvent.mDuration <= 0) {
+ throw new IllegalStateException("Delay has missing or invalid duration");
+ }
}
- } else if (COMMAND_INJECT.equals(mEvent.mCommand)) {
- if (mEvent.mInjections == null) {
- throw new IllegalStateException("Inject command is missing injection data");
+ case INJECT -> {
+ if (mEvent.mInjections == null) {
+ throw new IllegalStateException("Inject command is missing injection data");
+ }
}
- } else {
- throw new IllegalStateException("Unknown command " + mEvent.mCommand);
+ case SYNC -> {
+ if (mEvent.mSyncToken == null) {
+ throw new IllegalStateException("Sync command is missing sync token");
+ }
+ }
}
return mEvent;
}
@@ -276,6 +310,9 @@
case "port":
eb.setInputport(mReader.nextString());
break;
+ case "syncToken":
+ eb.setSyncToken(mReader.nextString());
+ break;
default:
mReader.skipValue();
}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index 740578e..47b7a354 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -25,6 +25,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
+import java.util.Objects;
/**
* Uinput class encapsulates execution of "uinput" command. It parses the provided input stream
@@ -96,28 +97,27 @@
private void process(Event e) {
final int index = mDevices.indexOfKey(e.getId());
- if (index >= 0) {
- Device d = mDevices.valueAt(index);
- if (Event.COMMAND_DELAY.equals(e.getCommand())) {
- d.addDelay(e.getDuration());
- } else if (Event.COMMAND_INJECT.equals(e.getCommand())) {
- d.injectEvent(e.getInjections());
- } else {
- if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
- error("Device id=" + e.getId() + " is already registered. Ignoring event.");
- } else {
- error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
- }
+ if (index < 0) {
+ if (e.getCommand() != Event.Command.REGISTER) {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ return;
}
- } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
registerDevice(e);
- } else {
- Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ return;
+ }
+
+ final Device d = mDevices.valueAt(index);
+ switch (Objects.requireNonNull(e.getCommand())) {
+ case REGISTER ->
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ case INJECT -> d.injectEvent(e.getInjections());
+ case DELAY -> d.addDelay(e.getDuration());
+ case SYNC -> d.syncEvent(e.getSyncToken());
}
}
private void registerDevice(Event e) {
- if (!Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ if (!Event.Command.REGISTER.equals(e.getCommand())) {
throw new IllegalStateException(
"Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 4851279..d0d76a4 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -454,12 +454,11 @@
*/
protected void onStart() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
- if (mContext != null
+ if (allowsRegisterDefaultOnBackInvokedCallback() && mContext != null
&& WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = this::onBackPressed;
getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
- mDefaultBackCallback = null;
}
}
@@ -470,9 +469,18 @@
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
if (mDefaultBackCallback != null) {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
+ mDefaultBackCallback = null;
}
}
+ /**
+ * Whether this dialog allows to register the default onBackInvokedCallback.
+ * @hide
+ */
+ protected boolean allowsRegisterDefaultOnBackInvokedCallback() {
+ return true;
+ }
+
private static final String DIALOG_SHOWING_TAG = "android:dialogShowing";
private static final String DIALOG_HIERARCHY_TAG = "android:dialogHierarchy";
@@ -697,7 +705,8 @@
if (event.isTracking() && !event.isCanceled()) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
- if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
+ if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)
+ || !allowsRegisterDefaultOnBackInvokedCallback()) {
onBackPressed();
return true;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 44068dd..ced3554 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2892,11 +2892,6 @@
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
- if (person != null) {
- person.visitUris(visitor);
- }
-
final RemoteInputHistoryItem[] history = extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
RemoteInputHistoryItem.class);
@@ -2908,9 +2903,14 @@
}
}
}
- }
- if (isStyle(MessagingStyle.class) && extras != null) {
+ // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+ // Notification Listeners might use directly (without the isStyle check).
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+ if (person != null) {
+ person.visitUris(visitor);
+ }
+
final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
Parcelable.class);
if (!ArrayUtils.isEmpty(messages)) {
@@ -2930,9 +2930,8 @@
}
visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
- }
- if (isStyle(CallStyle.class) & extras != null) {
+ // Extras for CallStyle (same reason for visiting without checking isStyle).
Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
callPerson.visitUris(visitor);
@@ -12783,7 +12782,6 @@
} else {
mBackgroundColor = rawColor;
}
- mProtectionColor = COLOR_INVALID; // filled in at the end
mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
ContrastColorUtil.resolvePrimaryColor(ctx, mBackgroundColor, nightMode),
mBackgroundColor, 4.5);
@@ -12800,7 +12798,6 @@
} else {
int[] attrs = {
R.attr.colorSurface,
- R.attr.colorBackgroundFloating,
R.attr.textColorPrimary,
R.attr.textColorSecondary,
R.attr.colorAccent,
@@ -12812,15 +12809,14 @@
};
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
mBackgroundColor = getColor(ta, 0, nightMode ? Color.BLACK : Color.WHITE);
- mProtectionColor = getColor(ta, 1, COLOR_INVALID);
- mPrimaryTextColor = getColor(ta, 2, COLOR_INVALID);
- mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
- mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
- mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
- mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
- mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
- mErrorColor = getColor(ta, 8, COLOR_INVALID);
- mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
+ mPrimaryTextColor = getColor(ta, 1, COLOR_INVALID);
+ mSecondaryTextColor = getColor(ta, 2, COLOR_INVALID);
+ mPrimaryAccentColor = getColor(ta, 3, COLOR_INVALID);
+ mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID);
+ mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID);
+ mOnAccentTextColor = getColor(ta, 6, COLOR_INVALID);
+ mErrorColor = getColor(ta, 7, COLOR_INVALID);
+ mRippleAlpha = Color.alpha(getColor(ta, 8, 0x33ffffff));
}
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
mBackgroundColor, nightMode);
@@ -12853,9 +12849,7 @@
}
}
// make sure every color has a valid value
- if (mProtectionColor == COLOR_INVALID) {
- mProtectionColor = ColorUtils.blendARGB(mPrimaryTextColor, mBackgroundColor, 0.8f);
- }
+ mProtectionColor = ColorUtils.blendARGB(mPrimaryTextColor, mBackgroundColor, 0.9f);
}
/** calculates the contrast color for the non-colorized notifications */
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 2b5175c..634089b 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -248,6 +248,13 @@
public boolean topActivityEligibleForUserAspectRatioButton;
/**
+ * Whether the user has forced the activity to be fullscreen through the user aspect ratio
+ * settings.
+ * @hide
+ */
+ public boolean isUserFullscreenOverrideEnabled;
+
+ /**
* Hint about the letterbox state of the top activity.
* @hide
*/
@@ -543,7 +550,8 @@
&& isSleeping == that.isSleeping
&& Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
&& parentTaskId == that.parentTaskId
- && Objects.equals(topActivity, that.topActivity);
+ && Objects.equals(topActivity, that.topActivity)
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
}
/**
@@ -574,7 +582,8 @@
&& (!hasCompatUI() || configuration.getLayoutDirection()
== that.configuration.getLayoutDirection())
&& (!hasCompatUI() || configuration.uiMode == that.configuration.uiMode)
- && (!hasCompatUI() || isVisible == that.isVisible);
+ && (!hasCompatUI() || isVisible == that.isVisible)
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
}
/**
@@ -630,6 +639,7 @@
topActivityLetterboxHorizontalPosition = source.readInt();
topActivityLetterboxWidth = source.readInt();
topActivityLetterboxHeight = source.readInt();
+ isUserFullscreenOverrideEnabled = source.readBoolean();
}
/**
@@ -686,6 +696,7 @@
dest.writeInt(topActivityLetterboxHorizontalPosition);
dest.writeInt(topActivityLetterboxWidth);
dest.writeInt(topActivityLetterboxHeight);
+ dest.writeBoolean(isUserFullscreenOverrideEnabled);
}
@Override
@@ -732,6 +743,7 @@
+ topActivityLetterboxHorizontalPosition
+ " topActivityLetterboxWidth=" + topActivityLetterboxWidth
+ " topActivityLetterboxHeight=" + topActivityLetterboxHeight
+ + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled
+ " locusId=" + mTopActivityLocusId
+ " displayAreaFeatureId=" + displayAreaFeatureId
+ " cameraCompatControlState="
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index c3df17d..529363f 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -344,15 +344,22 @@
// If there is a label for the launcher intent, then use that as it is typically shorter.
// Otherwise, just use the top-level application name.
Intent launchIntent = pm.getLaunchIntentForPackage(mContext.getPackageName());
+ if (launchIntent == null) {
+ return getDefaultCallingApplicationLabel();
+ }
List<ResolveInfo> infos =
pm.queryIntentActivities(
launchIntent, PackageManager.ResolveInfoFlags.of(MATCH_DEFAULT_ONLY));
if (infos.size() > 0) {
return infos.get(0).loadLabel(pm);
}
+ return getDefaultCallingApplicationLabel();
+ }
+
+ private CharSequence getDefaultCallingApplicationLabel() {
return mContext.getApplicationInfo()
.loadSafeLabel(
- pm,
+ mContext.getPackageManager(),
/* ellipsizeDip= */ 0,
TextUtils.SAFE_STRING_FLAG_SINGLE_LINE
| TextUtils.SAFE_STRING_FLAG_TRIM);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4b883cd..537e7d4 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2978,6 +2978,8 @@
* <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
* <li>The app being installed targets:
* <ul>
+ * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
+ * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
* <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on
* Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
* <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b>
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index c2a0062..eedb25b 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -123,7 +123,7 @@
* credential, display a picker when multiple credentials exist, etc.
* Callers (e.g. browsers) may optionally set origin in {@link GetCredentialRequest} for an
* app different from their own, to be able to get credentials on behalf of that app. They would
- * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN}
+ * need additional permission {@code CREDENTIAL_MANAGER_SET_ORIGIN}
* to use this functionality
*
* @param context the context used to launch any UI needed; use an activity context to make sure
@@ -209,9 +209,9 @@
*
* <p>This API doesn't invoke any UI. It only performs the preparation work so that you can
* later launch the remaining get-credential operation (involves UIs) through the {@link
- * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Context,
+ * #getCredential(Context, PrepareGetCredentialResponse.PendingGetCredentialHandle,
* CancellationSignal, Executor, OutcomeReceiver)} API which incurs less latency compared to
- * the {@link #getCredential(GetCredentialRequest, Context, CancellationSignal, Executor,
+ * the {@link #getCredential(Context, GetCredentialRequest, CancellationSignal, Executor,
* OutcomeReceiver)} API that executes the whole operation in one call.
*
* @param request the request specifying type(s) of credentials to get from the user
@@ -261,7 +261,7 @@
* storing the new credential, etc.
* Callers (e.g. browsers) may optionally set origin in {@link CreateCredentialRequest} for an
* app different from their own, to be able to get credentials on behalf of that app. They would
- * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN}
+ * need additional permission {@code CREDENTIAL_MANAGER_SET_ORIGIN}
* to use this functionality
*
* @param context the context used to launch any UI needed; use an activity context to make sure
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 6baf91d7..ea951a5 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -236,9 +236,10 @@
private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
new CameraExtensionManagerGlobal();
private final Object mLock = new Object();
- private final int PROXY_SERVICE_DELAY_MS = 1000;
+ private final int PROXY_SERVICE_DELAY_MS = 2000;
private InitializerFuture mInitFuture = null;
private ServiceConnection mConnection = null;
+ private int mConnectionCount = 0;
private ICameraExtensionsProxyService mProxy = null;
private boolean mSupportsAdvancedExtensions = false;
@@ -249,6 +250,15 @@
return GLOBAL_CAMERA_MANAGER;
}
+ private void releaseProxyConnectionLocked(Context ctx) {
+ if (mConnection != null ) {
+ ctx.unbindService(mConnection);
+ mConnection = null;
+ mProxy = null;
+ mConnectionCount = 0;
+ }
+ }
+
private void connectToProxyLocked(Context ctx) {
if (mConnection == null) {
Intent intent = new Intent();
@@ -270,7 +280,6 @@
mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName component) {
- mInitFuture.setStatus(false);
mConnection = null;
mProxy = null;
}
@@ -348,23 +357,32 @@
public boolean registerClient(Context ctx, IBinder token) {
synchronized (mLock) {
+ boolean ret = false;
connectToProxyLocked(ctx);
if (mProxy == null) {
return false;
}
+ mConnectionCount++;
try {
- return mProxy.registerClient(token);
+ ret = mProxy.registerClient(token);
} catch (RemoteException e) {
Log.e(TAG, "Failed to initialize extension! Extension service does "
+ " not respond!");
}
+ if (!ret) {
+ mConnectionCount--;
+ }
- return false;
+ if (mConnectionCount <= 0) {
+ releaseProxyConnectionLocked(ctx);
+ }
+
+ return ret;
}
}
- public void unregisterClient(IBinder token) {
+ public void unregisterClient(Context ctx, IBinder token) {
synchronized (mLock) {
if (mProxy != null) {
try {
@@ -372,6 +390,11 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to de-initialize extension! Extension service does"
+ " not respond!");
+ } finally {
+ mConnectionCount--;
+ if (mConnectionCount <= 0) {
+ releaseProxyConnectionLocked(ctx);
+ }
}
}
}
@@ -446,8 +469,8 @@
/**
* @hide
*/
- public static void unregisterClient(IBinder token) {
- CameraExtensionManagerGlobal.get().unregisterClient(token);
+ public static void unregisterClient(Context ctx, IBinder token) {
+ CameraExtensionManagerGlobal.get().unregisterClient(ctx, token);
}
/**
@@ -578,7 +601,7 @@
}
}
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableList(ret);
@@ -626,7 +649,7 @@
Log.e(TAG, "Failed to query the extension for postview availability! Extension "
+ "service does not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return false;
@@ -722,7 +745,7 @@
+ "service does not respond!");
return Collections.emptyList();
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
}
@@ -791,7 +814,7 @@
+ " not respond!");
return new ArrayList<>();
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
}
@@ -872,7 +895,7 @@
}
}
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
@@ -957,7 +980,7 @@
Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
+ " not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return null;
@@ -998,7 +1021,7 @@
Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
+ " not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return false;
@@ -1075,7 +1098,7 @@
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture request keys!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableSet(ret);
@@ -1155,7 +1178,7 @@
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture result keys!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableSet(ret);
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index ae700a0..f0fb2f9 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -90,7 +90,7 @@
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
private RequestProcessor mRequestProcessor = new RequestProcessor();
private final int mSessionId;
- private final IBinder mToken;
+ private IBinder mToken = null;
private Surface mClientRepeatingRequestSurface;
private Surface mClientCaptureSurface;
@@ -103,6 +103,8 @@
private boolean mInitialized;
private boolean mSessionClosed;
+ private final Context mContext;
+
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -113,14 +115,9 @@
public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
@NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@NonNull Map<String, CameraCharacteristics> characteristicsMap,
- @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId)
+ @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId,
+ @NonNull IBinder token)
throws CameraAccessException, RemoteException {
- final IBinder token = new Binder(TAG + " : " + sessionId);
- boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
- if (!success) {
- throw new UnsupportedOperationException("Unsupported extension!");
- }
-
String cameraId = cameraDevice.getId();
CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
cameraId, characteristicsMap);
@@ -204,8 +201,9 @@
IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
config.getExtension());
extender.init(cameraId, characteristicsMapNative);
- CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(extender,
- cameraDevice, characteristicsMapNative, repeatingRequestSurface,
+
+ CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(ctx,
+ extender, cameraDevice, characteristicsMapNative, repeatingRequestSurface,
burstCaptureSurface, postviewSurface, config.getStateCallback(),
config.getExecutor(), sessionId, token);
@@ -217,13 +215,16 @@
return ret;
}
- private CameraAdvancedExtensionSessionImpl(@NonNull IAdvancedExtenderImpl extender,
+ private CameraAdvancedExtensionSessionImpl(Context ctx,
+ @NonNull IAdvancedExtenderImpl extender,
@NonNull CameraDeviceImpl cameraDevice,
Map<String, CameraMetadataNative> characteristicsMap,
@Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
@Nullable Surface postviewSurface,
@NonNull StateCallback callback, @NonNull Executor executor,
- int sessionId, @NonNull IBinder token) {
+ int sessionId,
+ @NonNull IBinder token) {
+ mContext = ctx;
mAdvancedExtender = extender;
mCameraDevice = cameraDevice;
mCharacteristicsMap = characteristicsMap;
@@ -578,12 +579,16 @@
mSessionProcessor = null;
}
- CameraExtensionCharacteristics.unregisterClient(mToken);
- if (mInitialized || (mCaptureSession != null)) {
- notifyClose = true;
- CameraExtensionCharacteristics.releaseSession();
+
+ if (mToken != null) {
+ if (mInitialized || (mCaptureSession != null)) {
+ notifyClose = true;
+ CameraExtensionCharacteristics.releaseSession();
+ }
+ CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
}
mInitialized = false;
+ mToken = null;
for (ImageReader reader : mReaderMap.values()) {
reader.close();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d3bde4b..181ab2c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2550,19 +2550,32 @@
HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>(
mPhysicalIdsToChars);
characteristicsMap.put(mCameraId, mCharacteristics);
+ boolean initializationFailed = true;
+ IBinder token = new Binder(TAG + " : " + mNextSessionId++);
try {
+ boolean ret = CameraExtensionCharacteristics.registerClient(mContext, token);
+ if (!ret) {
+ token = null;
+ throw new UnsupportedOperationException("Unsupported extension!");
+ }
+
if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
mCurrentAdvancedExtensionSession =
CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
this, characteristicsMap, mContext, extensionConfiguration,
- mNextSessionId++);
+ mNextSessionId, token);
} else {
mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
this, characteristicsMap, mContext, extensionConfiguration,
- mNextSessionId++);
+ mNextSessionId, token);
}
+ initializationFailed = false;
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+ } finally {
+ if (initializationFailed && (token != null)) {
+ CameraExtensionCharacteristics.unregisterClient(mContext, token);
+ }
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 1db4808..7b7d7de 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -91,7 +91,7 @@
private final Set<CaptureRequest.Key> mSupportedRequestKeys;
private final Set<CaptureResult.Key> mSupportedResultKeys;
private final ExtensionSessionStatsAggregator mStatsAggregator;
- private final IBinder mToken;
+ private IBinder mToken = null;
private boolean mCaptureResultsSupported;
private CameraCaptureSession mCaptureSession = null;
@@ -119,6 +119,8 @@
// will do so internally.
private boolean mInternalRepeatingRequestEnabled = true;
+ private final Context mContext;
+
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -135,14 +137,9 @@
@NonNull Map<String, CameraCharacteristics> characteristicsMap,
@NonNull Context ctx,
@NonNull ExtensionSessionConfiguration config,
- int sessionId)
+ int sessionId,
+ @NonNull IBinder token)
throws CameraAccessException, RemoteException {
- final IBinder token = new Binder(TAG + " : " + sessionId);
- boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
- if (!success) {
- throw new UnsupportedOperationException("Unsupported extension!");
- }
-
String cameraId = cameraDevice.getId();
CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
cameraId, characteristicsMap);
@@ -234,6 +231,7 @@
characteristicsMap.get(cameraId).getNativeMetadata());
CameraExtensionSessionImpl session = new CameraExtensionSessionImpl(
+ ctx,
extenders.second,
extenders.first,
supportedPreviewSizes,
@@ -256,7 +254,7 @@
return session;
}
- public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
+ public CameraExtensionSessionImpl(Context ctx, @NonNull IImageCaptureExtenderImpl imageExtender,
@NonNull IPreviewExtenderImpl previewExtender,
@NonNull List<Size> previewSizes,
@NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@@ -269,6 +267,7 @@
@NonNull IBinder token,
@NonNull Set<CaptureRequest.Key> requestKeys,
@Nullable Set<CaptureResult.Key> resultKeys) {
+ mContext = ctx;
mImageExtender = imageExtender;
mPreviewExtender = previewExtender;
mCameraDevice = cameraDevice;
@@ -878,12 +877,15 @@
+ " respond!");
}
- CameraExtensionCharacteristics.unregisterClient(mToken);
- if (mInitialized || (mCaptureSession != null)) {
- notifyClose = true;
- CameraExtensionCharacteristics.releaseSession();
+ if (mToken != null) {
+ if (mInitialized || (mCaptureSession != null)) {
+ notifyClose = true;
+ CameraExtensionCharacteristics.releaseSession();
+ }
+ CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
}
mInitialized = false;
+ mToken = null;
if (mRepeatingRequestImageCallback != null) {
mRepeatingRequestImageCallback.close();
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 94bff89..4700720 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -370,8 +370,9 @@
/**
* Returns the default size of the surface associated with the display, or null if the surface
- * is not provided for layer mirroring by SurfaceFlinger.
- * Only used for mirroring started from MediaProjection.
+ * is not provided for layer mirroring by SurfaceFlinger. Size is rotated to reflect the current
+ * display device orientation.
+ * Used for mirroring from MediaProjection, or a physical display based on display flags.
*/
public abstract Point getDisplaySurfaceDefaultSize(int displayId);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 795eb4a..8f653b3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -576,6 +576,12 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long DISALLOW_INPUT_METHOD_INTERFACE_OVERRIDE = 148086656L;
+ /**
+ * Enable the logic to allow hiding the IME caption bar ("fake" IME navigation bar).
+ * @hide
+ */
+ public static final boolean ENABLE_HIDE_IME_CAPTION_BAR = true;
+
LayoutInflater mInflater;
TypedArray mThemeAttrs;
@UnsupportedAppUsage
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 78388ef..c01664e 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -16,6 +16,8 @@
package android.inputmethodservice;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
+import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import android.animation.ValueAnimator;
@@ -230,6 +232,16 @@
setIconTintInternal(calculateTargetDarkIntensity(mAppearance,
mDrawLegacyNavigationBarBackground));
+
+ if (ENABLE_HIDE_IME_CAPTION_BAR) {
+ mNavigationBarFrame.setOnApplyWindowInsetsListener((view, insets) -> {
+ if (mNavigationBarFrame != null) {
+ boolean visible = insets.isVisible(captionBar());
+ mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ return view.onApplyWindowInsets(insets);
+ });
+ }
}
private void uninstallNavigationBarFrameIfNecessary() {
@@ -240,6 +252,9 @@
if (parent instanceof ViewGroup) {
((ViewGroup) parent).removeView(mNavigationBarFrame);
}
+ if (ENABLE_HIDE_IME_CAPTION_BAR) {
+ mNavigationBarFrame.setOnApplyWindowInsetsListener(null);
+ }
mNavigationBarFrame = null;
}
@@ -414,7 +429,9 @@
decor.bringChildToFront(mNavigationBarFrame);
}
}
- mNavigationBarFrame.setVisibility(View.VISIBLE);
+ if (!ENABLE_HIDE_IME_CAPTION_BAR) {
+ mNavigationBarFrame.setVisibility(View.VISIBLE);
+ }
}
}
@@ -435,6 +452,11 @@
mShouldShowImeSwitcherWhenImeIsShown;
mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
+ if (ENABLE_HIDE_IME_CAPTION_BAR) {
+ mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
+ .setImeCaptionBarInsetsHeight(getImeCaptionBarHeight());
+ }
+
if (imeDrawsImeNavBar) {
installNavigationBarFrameIfNecessary();
if (mNavigationBarFrame == null) {
@@ -528,6 +550,16 @@
return drawLegacyNavigationBarBackground;
}
+ /**
+ * Returns the height of the IME caption bar if this should be shown, or {@code 0} instead.
+ */
+ private int getImeCaptionBarHeight() {
+ return mImeDrawsImeNavBar
+ ? mService.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_frame_height)
+ : 0;
+ }
+
@Override
public String toDebugString() {
return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 5704dac..e4a09a6 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -79,6 +79,13 @@
@WindowState
private int mWindowState = WindowState.TOKEN_PENDING;
+ @Override
+ protected boolean allowsRegisterDefaultOnBackInvokedCallback() {
+ // Do not register OnBackInvokedCallback from Dialog#onStart, InputMethodService will
+ // register CompatOnBackInvokedCallback for input method window.
+ return false;
+ }
+
/**
* Set {@link IBinder} window token to the window.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index be38df7..1cf41cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9975,6 +9975,13 @@
public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory";
/**
+ * Stores a boolean that defines whether the CSD as a feature is enabled or not.
+ * @hide
+ */
+ public static final String AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED =
+ "audio_safe_csd_as_a_feature_enabled";
+
+ /**
* Indicates whether notification display on the lock screen is enabled.
* <p>
* Type: int (0 for false, 1 for true)
@@ -10491,6 +10498,14 @@
"assist_long_press_home_enabled";
/**
+ * Whether press and hold on nav handle can trigger search.
+ *
+ * @hide
+ */
+ public static final String SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED =
+ "search_press_hold_nav_handle_enabled";
+
+ /**
* Control whether Trust Agents are in active unlock or extend unlock mode.
* @hide
*/
@@ -11114,6 +11129,19 @@
"navigation_mode";
/**
+ * The value is from another(source) device's {@link #NAVIGATION_MODE} during restore.
+ * It's supposed to be written only by
+ * {@link com.android.providers.settings.SettingsHelper}.
+ * This setting should not be added into backup array.
+ * <p>Value: -1 = Can't get value from restore(default),
+ * 0 = 3 button,
+ * 1 = 2 button,
+ * 2 = fully gestural.
+ * @hide
+ */
+ public static final String NAVIGATION_MODE_RESTORE = "navigation_mode_restore";
+
+ /**
* Scale factor for the back gesture inset size on the left side of the screen.
* @hide
*/
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 75640bd..f3b4c6d 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -92,6 +92,7 @@
mapParcel.recycle();
if (buffer != null) {
mRankingMapFd.unmap(buffer);
+ mRankingMapFd.close();
}
}
} else {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 708ebdf..a4989af 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -67,6 +67,7 @@
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
+import com.android.internal.infra.AndroidFuture;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -1702,6 +1703,11 @@
Slog.i(TAG, "onProcessRestarted");
mHandler.sendEmptyMessage(MSG_PROCESS_RESTARTED);
}
+
+ @Override
+ public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+ throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+ }
}
void onDetectorRemoteException() {
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index d9ee859..ccf8b67 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -227,6 +227,12 @@
public void stopDetection() {
HotwordDetectionService.this.onStopDetection();
}
+
+ @Override
+ public void registerRemoteStorageService(IDetectorSessionStorageService
+ detectorSessionStorageService) {
+ throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+ }
};
@Override
diff --git a/core/java/android/service/voice/IDetectorSessionStorageService.aidl b/core/java/android/service/voice/IDetectorSessionStorageService.aidl
new file mode 100644
index 0000000..592373e
--- /dev/null
+++ b/core/java/android/service/voice/IDetectorSessionStorageService.aidl
@@ -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 android.service.voice;
+
+import com.android.internal.infra.AndroidFuture;
+
+/**
+ * @hide
+ */
+oneway interface IDetectorSessionStorageService {
+ /**
+ * Called when a file open request is sent. Only files with the given names under the internal
+ * app storage, i.e., {@link Context#getFilesDir()} can be opened.
+ */
+ void openFile(in String filename, in AndroidFuture future);
+}
diff --git a/core/java/android/service/voice/ISandboxedDetectionService.aidl b/core/java/android/service/voice/ISandboxedDetectionService.aidl
index 098536d..c76ac28 100644
--- a/core/java/android/service/voice/ISandboxedDetectionService.aidl
+++ b/core/java/android/service/voice/ISandboxedDetectionService.aidl
@@ -24,6 +24,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.SharedMemory;
+import android.service.voice.IDetectorSessionStorageService;
import android.service.voice.IDetectorSessionVisualQueryDetectionCallback;
import android.service.voice.IDspHotwordDetectionCallback;
import android.view.contentcapture.IContentCaptureManager;
@@ -71,4 +72,10 @@
void ping(in IRemoteCallback callback);
void stopDetection();
+
+ /**
+ * Registers the interface stub to talk to the voice interaction service for initialization/
+ * detection unrelated functionalities.
+ */
+ void registerRemoteStorageService(in IDetectorSessionStorageService detectorSessionStorageService);
}
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 7ab4faf..88c2111 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -36,6 +36,7 @@
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.infra.AndroidFuture;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -299,6 +300,11 @@
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
() -> mCallback.onHotwordDetectionServiceRestarted()));
}
+
+ @Override
+ public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+ throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+ }
}
/** @hide */
diff --git a/core/java/android/service/voice/VisualQueryDetectionService.java b/core/java/android/service/voice/VisualQueryDetectionService.java
index cbe7666..d184b1e 100644
--- a/core/java/android/service/voice/VisualQueryDetectionService.java
+++ b/core/java/android/service/voice/VisualQueryDetectionService.java
@@ -40,7 +40,12 @@
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import java.util.function.IntConsumer;
/**
@@ -86,6 +91,8 @@
private ContentCaptureManager mContentCaptureManager;
@Nullable
private IRecognitionServiceManager mIRecognitionServiceManager;
+ @Nullable
+ private IDetectorSessionStorageService mDetectorSessionStorageService;
private final ISandboxedDetectionService mInterface = new ISandboxedDetectionService.Stub() {
@@ -154,6 +161,12 @@
public void updateRecognitionServiceManager(IRecognitionServiceManager manager) {
mIRecognitionServiceManager = manager;
}
+
+ @Override
+ public void registerRemoteStorageService(IDetectorSessionStorageService
+ detectorSessionStorageService) {
+ mDetectorSessionStorageService = detectorSessionStorageService;
+ }
};
@Override
@@ -323,4 +336,23 @@
}
}
+ /**
+ * Overrides {@link Context#openFileInput} to read files with the given file names under the
+ * internal app storage of the {@link VoiceInteractionService}, i.e., only files stored in
+ * {@link Context#getFilesDir()} can be opened.
+ */
+ @Override
+ public @Nullable FileInputStream openFileInput(@NonNull String filename) throws
+ FileNotFoundException {
+ try {
+ AndroidFuture<ParcelFileDescriptor> future = new AndroidFuture<>();
+ mDetectorSessionStorageService.openFile(filename, future);
+ ParcelFileDescriptor pfd = future.get();
+ return new FileInputStream(pfd.getFileDescriptor());
+ } catch (RemoteException | ExecutionException | InterruptedException e) {
+ Log.w(TAG, "Cannot open file due to remote service failure");
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
}
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 93b7964..5d7f478 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -25,6 +25,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
import android.os.Binder;
@@ -37,7 +38,10 @@
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.infra.AndroidFuture;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -58,17 +62,18 @@
private final Callback mCallback;
private final Executor mExecutor;
+ private final Context mContext;
private final IVoiceInteractionManagerService mManagerService;
private final VisualQueryDetectorInitializationDelegate mInitializationDelegate;
VisualQueryDetector(
IVoiceInteractionManagerService managerService,
- @NonNull @CallbackExecutor Executor executor,
- Callback callback) {
+ @NonNull @CallbackExecutor Executor executor, Callback callback, Context context) {
mManagerService = managerService;
mCallback = callback;
mExecutor = executor;
mInitializationDelegate = new VisualQueryDetectorInitializationDelegate();
+ mContext = context;
}
/**
@@ -245,7 +250,7 @@
@Override
void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
initAndVerifyDetector(options, sharedMemory,
- new InitializationStateListener(mExecutor, mCallback),
+ new InitializationStateListener(mExecutor, mCallback, mContext),
DETECTOR_TYPE_VISUAL_QUERY_DETECTOR);
}
@@ -330,9 +335,12 @@
private final Executor mExecutor;
private final Callback mCallback;
- InitializationStateListener(Executor executor, Callback callback) {
+ private final Context mContext;
+
+ InitializationStateListener(Executor executor, Callback callback, Context context) {
this.mExecutor = executor;
this.mCallback = callback;
+ this.mContext = context;
}
@Override
@@ -426,5 +434,22 @@
!TextUtils.isEmpty(errorMessage) ? errorMessage : "Error data is null");
}));
}
+ @Override
+ public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+ Slog.v(TAG, "BinderCallback#onOpenFile " + filename);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ Slog.v(TAG, "onOpenFile: " + filename);
+ File f = new File(mContext.getFilesDir(), filename);
+ ParcelFileDescriptor pfd = null;
+ try {
+ Slog.d(TAG, "opened a file with ParcelFileDescriptor.");
+ pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "Cannot open file. No ParcelFileDescriptor returned.");
+ } finally {
+ future.complete(pfd);
+ }
+ }));
+ }
}
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index ab9ae0a..de2a99b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -965,7 +965,7 @@
}
VisualQueryDetector visualQueryDetector =
- new VisualQueryDetector(mSystemService, executor, callback);
+ new VisualQueryDetector(mSystemService, executor, callback, this);
HotwordDetector visualQueryDetectorInitializationDelegate =
visualQueryDetector.getInitializationDelegate();
mActiveDetectors.add(visualQueryDetectorInitializationDelegate);
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 9656f36..7f313c1 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.ref.WeakReference;
@@ -232,39 +233,68 @@
intent,
attributionSource,
new ModelDownloadListener() {
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mIsTerminated = false;
+
@Override
public void onProgress(int completedPercent) {
- try {
- listener.onProgress(completedPercent);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mLock) {
+ if (mIsTerminated) {
+ return;
+ }
+ try {
+ listener.onProgress(completedPercent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@Override
public void onSuccess() {
- try {
- listener.onSuccess();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mLock) {
+ if (mIsTerminated) {
+ return;
+ }
+ mIsTerminated = true;
+ try {
+ listener.onSuccess();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@Override
public void onScheduled() {
- try {
- listener.onScheduled();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mLock) {
+ if (mIsTerminated) {
+ return;
+ }
+ mIsTerminated = true;
+ try {
+ listener.onScheduled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@Override
public void onError(int error) {
- try {
- listener.onError(error);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mLock) {
+ if (mIsTerminated) {
+ return;
+ }
+ mIsTerminated = true;
+ try {
+ listener.onError(error);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
});
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4b96d74..0b2b6ce 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -375,6 +375,14 @@
public static final int FLAG_REAR = 1 << 13;
/**
+ * Display flag: Indicates that the orientation of this display is not fixed and is coupled to
+ * the orientation of its content.
+ *
+ * @hide
+ */
+ public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 14;
+
+ /**
* Display flag: Indicates that the contents of the display should not be scaled
* to fit the physical screen dimensions. Used for development only to emulate
* devices with smaller physicals screens while preserving density.
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 4cfec99..9b34007 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -19,7 +19,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
@@ -78,11 +81,17 @@
private int mConnectionCount = 0;
private final InputMethodManager mImm;
+ private final RectF mTempRectF = new RectF();
+
+ private final Region mTempRegion = new Region();
+
+ private final Matrix mTempMatrix = new Matrix();
+
/**
* The handwrite-able View that is currently the target of a hovering stylus pointer. This is
* used to help determine whether the handwriting PointerIcon should be shown in
* {@link #onResolvePointerIcon(Context, MotionEvent)} so that we can reduce the number of calls
- * to {@link #findBestCandidateView(float, float)}.
+ * to {@link #findBestCandidateView(float, float, boolean)}.
*/
@Nullable
private WeakReference<View> mCachedHoverTarget = null;
@@ -189,8 +198,8 @@
final float y = motionEvent.getY(pointerIndex);
if (largerThanTouchSlop(x, y, mState.mStylusDownX, mState.mStylusDownY)) {
mState.mExceedHandwritingSlop = true;
- View candidateView =
- findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY);
+ View candidateView = findBestCandidateView(mState.mStylusDownX,
+ mState.mStylusDownY, /* isHover */ false);
if (candidateView != null) {
if (candidateView == getConnectedView()) {
if (!candidateView.hasFocus()) {
@@ -398,13 +407,14 @@
final View cachedHoverTarget = getCachedHoverTarget();
if (cachedHoverTarget != null) {
final Rect handwritingArea = getViewHandwritingArea(cachedHoverTarget);
- if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget)
+ if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
+ /* isHover */ true)
&& shouldTriggerStylusHandwritingForView(cachedHoverTarget)) {
return cachedHoverTarget;
}
}
- final View candidateView = findBestCandidateView(hoverX, hoverY);
+ final View candidateView = findBestCandidateView(hoverX, hoverY, /* isHover */ true);
if (candidateView != null) {
mCachedHoverTarget = new WeakReference<>(candidateView);
@@ -434,14 +444,14 @@
* @param y the y coordinates of the stylus event, in the coordinates of the window.
*/
@Nullable
- private View findBestCandidateView(float x, float y) {
+ private View findBestCandidateView(float x, float y, boolean isHover) {
// If the connectedView is not null and do not set any handwriting area, it will check
// whether the connectedView's boundary contains the initial stylus position. If true,
// directly return the connectedView.
final View connectedView = getConnectedView();
if (connectedView != null) {
Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (isInHandwritingArea(handwritingArea, x, y, connectedView)
+ if (isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
&& shouldTriggerStylusHandwritingForView(connectedView)) {
return connectedView;
}
@@ -455,7 +465,7 @@
for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
final View view = viewInfo.getView();
final Rect handwritingArea = viewInfo.getHandwritingArea();
- if (!isInHandwritingArea(handwritingArea, x, y, view)
+ if (!isInHandwritingArea(handwritingArea, x, y, view, isHover)
|| !shouldTriggerStylusHandwritingForView(view)) {
continue;
}
@@ -551,15 +561,48 @@
* Return true if the (x, y) is inside by the given {@link Rect} with the View's
* handwriting bounds with offsets applied.
*/
- private static boolean isInHandwritingArea(@Nullable Rect handwritingArea,
- float x, float y, View view) {
+ private boolean isInHandwritingArea(@Nullable Rect handwritingArea,
+ float x, float y, View view, boolean isHover) {
if (handwritingArea == null) return false;
- return contains(handwritingArea, x, y,
+ if (!contains(handwritingArea, x, y,
view.getHandwritingBoundsOffsetLeft(),
view.getHandwritingBoundsOffsetTop(),
view.getHandwritingBoundsOffsetRight(),
- view.getHandwritingBoundsOffsetBottom());
+ view.getHandwritingBoundsOffsetBottom())) {
+ return false;
+ }
+
+ // The returned handwritingArea computed by ViewParent#getChildVisibleRect didn't consider
+ // the case where a view is stacking on top of the editor. (e.g. DrawerLayout, popup)
+ // We must check the hit region of the editor again, and avoid the case where another
+ // view on top of the editor is handling MotionEvents.
+ ViewParent parent = view.getParent();
+ if (parent == null) {
+ return true;
+ }
+
+ Region region = mTempRegion;
+ mTempRegion.set(0, 0, view.getWidth(), view.getHeight());
+ Matrix matrix = mTempMatrix;
+ matrix.reset();
+ if (!parent.getChildLocalHitRegion(view, region, matrix, isHover)) {
+ return false;
+ }
+
+ // It's not easy to extend the region by the given handwritingBoundsOffset. Instead, we
+ // create a rectangle surrounding the motion event location and check if this rectangle
+ // overlaps with the hit region of the editor.
+ float left = x - view.getHandwritingBoundsOffsetRight();
+ float top = y - view.getHandwritingBoundsOffsetBottom();
+ float right = Math.max(x + view.getHandwritingBoundsOffsetLeft(), left + 1);
+ float bottom = Math.max(y + view.getHandwritingBoundsOffsetTop(), top + 1);
+ RectF rectF = mTempRectF;
+ rectF.set(left, top, right, bottom);
+ matrix.mapRect(rectF);
+
+ return region.op(Math.round(rectF.left), Math.round(rectF.top),
+ Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
}
/**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 4ecfc40..c6d8bd1 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,10 +16,12 @@
package android.view;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.InsetsControllerProto.CONTROL;
import static android.view.InsetsControllerProto.STATE;
import static android.view.InsetsSource.ID_IME;
+import static android.view.InsetsSource.ID_IME_CAPTION_BAR;
import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.LAST;
@@ -40,6 +42,7 @@
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -652,6 +655,7 @@
private int mLastWindowingMode;
private boolean mStartingAnimation;
private int mCaptionInsetsHeight = 0;
+ private int mImeCaptionBarInsetsHeight = 0;
private boolean mAnimationsDisabled;
private boolean mCompatSysUiVisibilityStaled;
@@ -693,6 +697,9 @@
if (!CAPTION_ON_SHELL && source1.getType() == captionBar()) {
return;
}
+ if (source1.getId() == ID_IME_CAPTION_BAR) {
+ return;
+ }
// Don't change the indexes of the sources while traversing. Remove it later.
mPendingRemoveIndexes.add(index1);
@@ -823,6 +830,9 @@
if (mFrame.equals(frame)) {
return;
}
+ if (mImeCaptionBarInsetsHeight != 0) {
+ setImeCaptionBarInsetsHeight(mImeCaptionBarInsetsHeight);
+ }
mHost.notifyInsetsChanged();
mFrame.set(frame);
}
@@ -1007,6 +1017,12 @@
// Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+ if (consumer.getId() == ID_IME_CAPTION_BAR) {
+ // The inset control for the IME caption bar will never be dispatched
+ // by the server.
+ continue;
+ }
+
final InsetsSourceControl control = mTmpControlArray.get(consumer.getId());
if (control != null) {
controllableTypes |= control.getType();
@@ -1499,7 +1515,8 @@
continue;
}
final InsetsSourceControl control = consumer.getControl();
- if (control != null && control.getLeash() != null) {
+ if (control != null
+ && (control.getLeash() != null || control.getId() == ID_IME_CAPTION_BAR)) {
controls.put(control.getId(), new InsetsSourceControl(control));
typesReady |= consumer.getType();
}
@@ -1885,6 +1902,35 @@
}
@Override
+ public void setImeCaptionBarInsetsHeight(int height) {
+ if (!ENABLE_HIDE_IME_CAPTION_BAR) {
+ return;
+ }
+ Rect newFrame = new Rect(mFrame.left, mFrame.bottom - height, mFrame.right, mFrame.bottom);
+ InsetsSource source = mState.peekSource(ID_IME_CAPTION_BAR);
+ if (mImeCaptionBarInsetsHeight != height
+ || (source != null && !newFrame.equals(source.getFrame()))) {
+ mImeCaptionBarInsetsHeight = height;
+ if (mImeCaptionBarInsetsHeight != 0) {
+ mState.getOrCreateSource(ID_IME_CAPTION_BAR, captionBar())
+ .setFrame(newFrame);
+ getSourceConsumer(ID_IME_CAPTION_BAR, captionBar()).setControl(
+ new InsetsSourceControl(ID_IME_CAPTION_BAR, captionBar(),
+ null /* leash */, false /* initialVisible */,
+ new Point(), Insets.NONE),
+ new int[1], new int[1]);
+ } else {
+ mState.removeSource(ID_IME_CAPTION_BAR);
+ InsetsSourceConsumer sourceConsumer = mSourceConsumers.get(ID_IME_CAPTION_BAR);
+ if (sourceConsumer != null) {
+ sourceConsumer.setControl(null, new int[1], new int[1]);
+ }
+ }
+ mHost.notifyInsetsChanged();
+ }
+ }
+
+ @Override
public void setSystemBarsBehavior(@Behavior int behavior) {
mHost.setSystemBarsBehavior(behavior);
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 6441186..ff009ed 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -20,6 +20,7 @@
import static android.view.InsetsSourceProto.TYPE;
import static android.view.InsetsSourceProto.VISIBLE;
import static android.view.InsetsSourceProto.VISIBLE_FRAME;
+import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.ime;
import android.annotation.IntDef;
@@ -47,6 +48,9 @@
/** The insets source ID of IME */
public static final int ID_IME = createId(null, 0, ime());
+ /** The insets source ID of the IME caption bar ("fake" IME navigation bar). */
+ static final int ID_IME_CAPTION_BAR =
+ InsetsSource.createId(null /* owner */, 1 /* index */, captionBar());
/**
* Controls whether this source suppresses the scrim. If the scrim is ignored, the system won't
@@ -215,8 +219,12 @@
// During drag-move and drag-resizing, the caption insets position may not get updated
// before the app frame get updated. To layout the app content correctly during drag events,
// we always return the insets with the corresponding height covering the top.
+ // However, with the "fake" IME navigation bar treated as a caption bar, we return the
+ // insets with the corresponding height the bottom.
if (getType() == WindowInsets.Type.captionBar()) {
- return Insets.of(0, frame.height(), 0, 0);
+ return getId() == ID_IME_CAPTION_BAR
+ ? Insets.of(0, 0, 0, frame.height())
+ : Insets.of(0, frame.height(), 0, 0);
}
// Checks for whether there is shared edge with insets for 0-width/height window.
final boolean hasIntersection = relativeFrame.isEmpty()
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index e8f62fc..a4cbc52 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -44,6 +44,7 @@
private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
= new ArrayList<>();
private int mCaptionInsetsHeight = 0;
+ private int mImeCaptionBarInsetsHeight = 0;
private WindowInsetsAnimationControlListener mLoggingListener;
private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
@@ -91,6 +92,11 @@
}
@Override
+ public void setImeCaptionBarInsetsHeight(int height) {
+ mImeCaptionBarInsetsHeight = height;
+ }
+
+ @Override
public void setSystemBarsBehavior(int behavior) {
if (mReplayedInsetsController != null) {
mReplayedInsetsController.setSystemBarsBehavior(behavior);
@@ -168,6 +174,9 @@
if (mCaptionInsetsHeight != 0) {
controller.setCaptionInsetsHeight(mCaptionInsetsHeight);
}
+ if (mImeCaptionBarInsetsHeight != 0) {
+ controller.setImeCaptionBarInsetsHeight(mImeCaptionBarInsetsHeight);
+ }
if (mAnimationsDisabled) {
controller.setAnimationsDisabled(true);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c11f497..e673676 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -47,6 +47,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.gui.DropInputMode;
+import android.gui.StalledTransactionInfo;
import android.hardware.DataSpace;
import android.hardware.HardwareBuffer;
import android.hardware.OverlayProperties;
@@ -292,6 +293,7 @@
long nativeObject, long nativeTpc, TrustedPresentationThresholds thresholds);
private static native void nativeClearTrustedPresentationCallback(long transactionObj,
long nativeObject);
+ private static native StalledTransactionInfo nativeGetStalledTransactionInfo(int pid);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -4363,4 +4365,11 @@
callback.accept(fence);
}
+ /**
+ * @hide
+ */
+ public static StalledTransactionInfo getStalledTransactionInfo(int pid) {
+ return nativeGetStalledTransactionInfo(pid);
+ }
+
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b1098d..7bdff8c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7361,6 +7361,90 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+ @NonNull Matrix matrix, boolean isHover) {
+ if (!child.hasIdentityMatrix()) {
+ matrix.preConcat(child.getInverseMatrix());
+ }
+
+ final int dx = child.mLeft - mScrollX;
+ final int dy = child.mTop - mScrollY;
+ matrix.preTranslate(-dx, -dy);
+
+ final int width = mRight - mLeft;
+ final int height = mBottom - mTop;
+
+ // Map the bounds of this view into the region's coordinates and clip the region.
+ final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
+ rect.set(0, 0, width, height);
+ matrix.mapRect(rect);
+
+ boolean notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+ Math.round(rect.right), Math.round(rect.bottom), Region.Op.INTERSECT);
+
+ if (isHover) {
+ HoverTarget target = mFirstHoverTarget;
+ boolean childIsHit = false;
+ while (target != null) {
+ final HoverTarget next = target.next;
+ if (target.child == child) {
+ childIsHit = true;
+ break;
+ }
+ target = next;
+ }
+ if (!childIsHit) {
+ target = mFirstHoverTarget;
+ while (notEmpty && target != null) {
+ final HoverTarget next = target.next;
+ final View hoveredView = target.child;
+
+ rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight,
+ hoveredView.mBottom);
+ matrix.mapRect(rect);
+ notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+ Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE);
+ target = next;
+ }
+ }
+ } else {
+ TouchTarget target = mFirstTouchTarget;
+ boolean childIsHit = false;
+ while (target != null) {
+ final TouchTarget next = target.next;
+ if (target.child == child) {
+ childIsHit = true;
+ break;
+ }
+ target = next;
+ }
+ if (!childIsHit) {
+ target = mFirstTouchTarget;
+ while (notEmpty && target != null) {
+ final TouchTarget next = target.next;
+ final View touchedView = target.child;
+
+ rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight,
+ touchedView.mBottom);
+ matrix.mapRect(rect);
+ notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+ Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE);
+ target = next;
+ }
+ }
+ }
+
+ if (notEmpty && mParent != null) {
+ notEmpty = mParent.getChildLocalHitRegion(this, region, matrix, isHover);
+ }
+ return notEmpty;
+ }
+
+
private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
final int[] locationInWindow = new int[2];
view.getLocationInWindow(locationInWindow);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 1020d2e..54bc348 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
@@ -686,6 +687,36 @@
}
/**
+ * Compute the region where the child can receive the {@link MotionEvent}s from the root view.
+ *
+ * <p> Given region where the child will accept {@link MotionEvent}s.
+ * Modify the region to the unblocked region where the child can receive the
+ * {@link MotionEvent}s from the view root.
+ * </p>
+ *
+ * <p> The given region is always clipped by the bounds of the parent views. When there are
+ * on-going {@link MotionEvent}s, this method also makes use of the event dispatching results to
+ * determine whether a sibling view will also block the child's hit region.
+ * </p>
+ *
+ * @param child a child View, whose hit region we want to compute.
+ * @param region the initial hit region where the child view will handle {@link MotionEvent}s,
+ * defined in the child coordinates. Will be overwritten to the result hit region.
+ * @param matrix the matrix that maps the given child view's coordinates to the region
+ * coordinates. It will be modified to a matrix that maps window coordinates to
+ * the result region's coordinates.
+ * @param isHover if true it will return the hover events' hit region, otherwise it will
+ * return the touch events' hit region.
+ * @return true if the returned region is not empty.
+ * @hide
+ */
+ default boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+ @NonNull Matrix matrix, boolean isHover) {
+ region.setEmpty();
+ return false;
+ }
+
+ /**
* Unbuffered dispatch has been requested by a child of this view parent.
* This method is called by the View hierarchy to signal ancestors that a View needs to
* request unbuffered dispatch.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6edf0e2..c1ce5e0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -127,6 +127,7 @@
import android.graphics.PorterDuff;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
@@ -2393,6 +2394,22 @@
}
@Override
+ public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+ @NonNull Matrix matrix, boolean isHover) {
+ if (child != mView) {
+ throw new IllegalArgumentException("child " + child + " is not the root view "
+ + mView + " managed by this ViewRootImpl");
+ }
+
+ RectF rectF = new RectF(0, 0, mWidth, mHeight);
+ matrix.mapRect(rectF);
+ // Note: don't apply scroll offset, because we want to know its
+ // visibility in the virtual canvas being given to the view hierarchy.
+ return region.op(Math.round(rectF.left), Math.round(rectF.top),
+ Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
+ }
+
+ @Override
public void bringChildToFront(View child) {
}
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index bc0bab7..cc2cd79 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -250,6 +250,16 @@
void setCaptionInsetsHeight(int height);
/**
+ * Sets the insets height for the IME caption bar, which corresponds to the
+ * "fake" IME navigation bar.
+ *
+ * @param height the insets height of the IME caption bar.
+ * @hide
+ */
+ default void setImeCaptionBarInsetsHeight(int height) {
+ }
+
+ /**
* Controls the behavior of system bars.
*
* @param behavior Determines how the bars behave when being hidden by the application.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c576286..a00e797 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1302,7 +1302,7 @@
* ratio or orientation specified in the app manifest.
*
* <p>The aspect ratio compatibility override is exposed to users in device
- * settings. A menu in device settings lists all apps that don't opt out of
+ * settings. A menu in device settings lists all apps that have not opted out of
* the compatibility override. Users select apps from the menu and set the
* app aspect ratio on a per-app basis. Typically, the menu is available
* only on large screen devices.
@@ -1347,11 +1347,11 @@
* Application level
* {@link android.content.pm.PackageManager.Property PackageManager.Property}
* tag that (when set to false) informs the system the app has opted out of the
- * full-screen option of the aspect ratio compatibility override. (For
- * background information about the aspect ratio compatibility override, see
+ * full-screen option of the user aspect ratio compatibility override settings. (For
+ * background information about the user aspect ratio compatibility override, see
* {@link #PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE}.)
*
- * <p>When users apply the aspect ratio compatibility override, the orientation
+ * <p>When users apply the full-screen compatibility override, the orientation
* of the activity is forced to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER}.
*
* <p>The user override is intended to improve the app experience on devices
@@ -3839,6 +3839,7 @@
* @see #ROTATION_ANIMATION_ROTATE
* @see #ROTATION_ANIMATION_CROSSFADE
* @see #ROTATION_ANIMATION_JUMPCUT
+ * @see #ROTATION_ANIMATION_SEAMLESS
*/
public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index fea3b78..7903dd64 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -6945,6 +6945,7 @@
// something is going to start.
opts.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ opts.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
return Pair.create(intent, opts);
}
}
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index 3801188..ba87caa 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -22,6 +22,7 @@
import android.service.voice.HotwordRejectedResult;
import android.service.voice.SoundTriggerFailure;
import android.service.voice.VisualQueryDetectionServiceFailure;
+import com.android.internal.infra.AndroidFuture;
/**
* @hide
@@ -113,4 +114,9 @@
/** Called when the hotword detection process is restarted */
void onProcessRestarted();
+
+ /**
+ * Called when a file open request is sent.
+ */
+ void onOpenFile(in String filename, in AndroidFuture future);
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 7dda91d..5b6b360 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -410,9 +410,11 @@
// convert MessagingStyle.Message to MessagingMessage, re-using ones from a previous binding
// if they exist
final List<MessagingMessage> newMessagingMessages =
- createMessages(newMessages, false /* isHistoric */);
+ createMessages(newMessages, /* isHistoric= */false,
+ /* usePrecomputedText= */false);
final List<MessagingMessage> newHistoricMessagingMessages =
- createMessages(newHistoricMessages, true /* isHistoric */);
+ createMessages(newHistoricMessages, /* isHistoric= */true,
+ /* usePrecomputedText= */false);
// bind it, baby
bindViews(user, showSpinner, unreadCount,
newMessagingMessages,
@@ -981,15 +983,17 @@
* @param newMessages the messages to parse.
*/
private List<MessagingMessage> createMessages(
- List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
+ List<Notification.MessagingStyle.Message> newMessages, boolean isHistoric,
+ boolean usePrecomputedText) {
List<MessagingMessage> result = new ArrayList<>();
for (int i = 0; i < newMessages.size(); i++) {
Notification.MessagingStyle.Message m = newMessages.get(i);
MessagingMessage message = findAndRemoveMatchingMessage(m);
if (message == null) {
- message = MessagingMessage.createMessage(this, m, mImageResolver);
+ message = MessagingMessage.createMessage(this, m,
+ mImageResolver, usePrecomputedText);
}
- message.setIsHistoric(historic);
+ message.setIsHistoric(isHistoric);
result.add(message);
}
return result;
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 098bce1..c132d6a 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -93,8 +93,9 @@
}
@Override
- public boolean setMessage(Notification.MessagingStyle.Message message) {
- MessagingMessage.super.setMessage(message);
+ public boolean setMessage(Notification.MessagingStyle.Message message,
+ boolean usePrecomputedText) {
+ MessagingMessage.super.setMessage(message, usePrecomputedText);
Drawable drawable;
try {
Uri uri = message.getDataUri();
@@ -114,32 +115,42 @@
}
mDrawable = drawable;
mAspectRatio = ((float) mDrawable.getIntrinsicWidth()) / intrinsicHeight;
- setImageDrawable(drawable);
- setContentDescription(message.getText());
+ if (!usePrecomputedText) {
+ finalizeInflate();
+ }
return true;
}
static MessagingMessage createMessage(IMessagingLayout layout,
- Notification.MessagingStyle.Message m, ImageResolver resolver) {
+ Notification.MessagingStyle.Message m, ImageResolver resolver,
+ boolean usePrecomputedText) {
MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
MessagingImageMessage createdMessage = sInstancePool.acquire();
if (createdMessage == null) {
createdMessage = (MessagingImageMessage) LayoutInflater.from(
layout.getContext()).inflate(
- R.layout.notification_template_messaging_image_message,
- messagingLinearLayout,
- false);
+ R.layout.notification_template_messaging_image_message,
+ messagingLinearLayout,
+ false);
createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
}
createdMessage.setImageResolver(resolver);
- boolean created = createdMessage.setMessage(m);
- if (!created) {
+ // MessagingImageMessage does not use usePrecomputedText.
+ boolean populated = createdMessage.setMessage(m, /* usePrecomputedText= */false);
+ if (!populated) {
createdMessage.recycle();
- return MessagingTextMessage.createMessage(layout, m);
+ return MessagingTextMessage.createMessage(layout, m, usePrecomputedText);
}
return createdMessage;
}
+
+ @Override
+ public void finalizeInflate() {
+ setImageDrawable(mDrawable);
+ setContentDescription(getMessage().getText());
+ }
+
private void setImageResolver(ImageResolver resolver) {
mImageResolver = resolver;
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 8345c5c..83557cd 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -178,9 +178,9 @@
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
final List<MessagingMessage> historicMessagingMessages = createMessages(newHistoricMessages,
- true /* isHistoric */);
+ /* isHistoric= */true, /* usePrecomputedText= */ false);
final List<MessagingMessage> newMessagingMessages =
- createMessages(newMessages, false /* isHistoric */);
+ createMessages(newMessages, /* isHistoric= */false, /* usePrecomputedText= */false);
bindViews(user, showSpinner, historicMessagingMessages, newMessagingMessages);
}
@@ -518,15 +518,17 @@
* @param newMessages the messages to parse.
*/
private List<MessagingMessage> createMessages(
- List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
+ List<Notification.MessagingStyle.Message> newMessages, boolean isHistoric,
+ boolean usePrecomputedText) {
List<MessagingMessage> result = new ArrayList<>();
for (int i = 0; i < newMessages.size(); i++) {
Notification.MessagingStyle.Message m = newMessages.get(i);
MessagingMessage message = findAndRemoveMatchingMessage(m);
if (message == null) {
- message = MessagingMessage.createMessage(this, m, mImageResolver);
+ message = MessagingMessage.createMessage(this, m,
+ mImageResolver, usePrecomputedText);
}
- message.setIsHistoric(historic);
+ message.setIsHistoric(isHistoric);
result.add(message);
}
return result;
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index 5ecd3b8..ad90a63 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -34,11 +34,12 @@
String IMAGE_MIME_TYPE_PREFIX = "image/";
static MessagingMessage createMessage(IMessagingLayout layout,
- Notification.MessagingStyle.Message m, ImageResolver resolver) {
+ Notification.MessagingStyle.Message m, ImageResolver resolver,
+ boolean usePrecomputedText) {
if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) {
- return MessagingImageMessage.createMessage(layout, m, resolver);
+ return MessagingImageMessage.createMessage(layout, m, resolver, usePrecomputedText);
} else {
- return MessagingTextMessage.createMessage(layout, m);
+ return MessagingTextMessage.createMessage(layout, m, usePrecomputedText);
}
}
@@ -55,9 +56,11 @@
/**
* Set a message for this view.
+ *
* @return true if setting the message worked
*/
- default boolean setMessage(Notification.MessagingStyle.Message message) {
+ default boolean setMessage(Notification.MessagingStyle.Message message,
+ boolean usePrecomputedText) {
getState().setMessage(message);
return true;
}
@@ -151,4 +154,10 @@
void setVisibility(int visibility);
int getVisibility();
+
+ /**
+ * Finalize inflation of the MessagingMessages, which should be called on Main Thread.
+ * @hide
+ */
+ void finalizeInflate();
}
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
index 19791db..bd62aad 100644
--- a/core/java/com/android/internal/widget/MessagingTextMessage.java
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -23,7 +23,9 @@
import android.app.Notification;
import android.content.Context;
import android.text.Layout;
+import android.text.PrecomputedText;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
@@ -35,10 +37,13 @@
@RemoteViews.RemoteView
public class MessagingTextMessage extends ImageFloatingTextView implements MessagingMessage {
+ private static final String TAG = "MessagingTextMessage";
private static final MessagingPool<MessagingTextMessage> sInstancePool =
new MessagingPool<>(20);
private final MessagingMessageState mState = new MessagingMessageState(this);
+ private PrecomputedText mPrecomputedText = null;
+
public MessagingTextMessage(@NonNull Context context) {
super(context);
}
@@ -63,25 +68,32 @@
}
@Override
- public boolean setMessage(Notification.MessagingStyle.Message message) {
- MessagingMessage.super.setMessage(message);
- setText(message.getText());
+ public boolean setMessage(Notification.MessagingStyle.Message message,
+ boolean usePrecomputedText) {
+ MessagingMessage.super.setMessage(message, usePrecomputedText);
+ if (usePrecomputedText) {
+ mPrecomputedText = PrecomputedText.create(message.getText(), getTextMetricsParams());
+ } else {
+ setText(message.getText());
+ mPrecomputedText = null;
+ }
+
return true;
}
static MessagingMessage createMessage(IMessagingLayout layout,
- Notification.MessagingStyle.Message m) {
+ Notification.MessagingStyle.Message m, boolean usePrecomputedText) {
MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
MessagingTextMessage createdMessage = sInstancePool.acquire();
if (createdMessage == null) {
createdMessage = (MessagingTextMessage) LayoutInflater.from(
layout.getContext()).inflate(
- R.layout.notification_template_messaging_text_message,
- messagingLinearLayout,
- false);
+ R.layout.notification_template_messaging_text_message,
+ messagingLinearLayout,
+ false);
createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
}
- createdMessage.setMessage(m);
+ createdMessage.setMessage(m, usePrecomputedText);
return createdMessage;
}
@@ -135,4 +147,20 @@
public void setColor(int color) {
setTextColor(color);
}
+
+ @Override
+ public void finalizeInflate() {
+ try {
+ setText(mPrecomputedText != null ? mPrecomputedText
+ : getState().getMessage().getText());
+ } catch (IllegalArgumentException exception) {
+ Log.wtf(
+ /* tag = */ TAG,
+ /* msg = */ "PrecomputedText setText failed for TextView:" + this,
+ /* tr = */ exception
+ );
+ mPrecomputedText = null;
+ setText(getState().getMessage().getText());
+ }
+ }
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 4249253..dbe0338 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -257,6 +257,14 @@
jmethodID onTrustedPresentationChanged;
} gTrustedPresentationCallbackClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+ jfieldID layerName;
+ jfieldID bufferId;
+ jfieldID frameNumber;
+} gStalledTransactionInfoClassInfo;
+
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
@@ -2032,6 +2040,29 @@
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeTpc));
}
+static jobject nativeGetStalledTransactionInfo(JNIEnv* env, jclass clazz, jint pid) {
+ std::optional<gui::StalledTransactionInfo> stalledTransactionInfo =
+ SurfaceComposerClient::getStalledTransactionInfo(pid);
+ if (!stalledTransactionInfo) {
+ return nullptr;
+ }
+
+ jobject jStalledTransactionInfo = env->NewObject(gStalledTransactionInfoClassInfo.clazz,
+ gStalledTransactionInfoClassInfo.ctor);
+ if (!jStalledTransactionInfo) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
+ return nullptr;
+ }
+
+ env->SetObjectField(jStalledTransactionInfo, gStalledTransactionInfoClassInfo.layerName,
+ env->NewStringUTF(String8{stalledTransactionInfo->layerName}));
+ env->SetLongField(jStalledTransactionInfo, gStalledTransactionInfoClassInfo.bufferId,
+ static_cast<jlong>(stalledTransactionInfo->bufferId));
+ env->SetLongField(jStalledTransactionInfo, gStalledTransactionInfoClassInfo.frameNumber,
+ static_cast<jlong>(stalledTransactionInfo->frameNumber));
+ return jStalledTransactionInfo;
+}
+
// ----------------------------------------------------------------------------
SurfaceControl* android_view_SurfaceControl_getNativeSurfaceControl(JNIEnv* env,
@@ -2281,6 +2312,8 @@
{"nativeCreateTpc", "(Landroid/view/SurfaceControl$TrustedPresentationCallback;)J",
(void*)nativeCreateTpc},
{"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
+ {"nativeGetStalledTransactionInfo", "(I)Landroid/gui/StalledTransactionInfo;",
+ (void*) nativeGetStalledTransactionInfo },
// clang-format on
};
@@ -2524,6 +2557,18 @@
gTrustedPresentationCallbackClassInfo.onTrustedPresentationChanged =
GetMethodIDOrDie(env, trustedPresentationCallbackClazz, "onTrustedPresentationChanged",
"(Z)V");
+
+ jclass stalledTransactionInfoClazz = FindClassOrDie(env, "android/gui/StalledTransactionInfo");
+ gStalledTransactionInfoClassInfo.clazz = MakeGlobalRefOrDie(env, stalledTransactionInfoClazz);
+ gStalledTransactionInfoClassInfo.ctor =
+ GetMethodIDOrDie(env, stalledTransactionInfoClazz, "<init>", "()V");
+ gStalledTransactionInfoClassInfo.layerName =
+ GetFieldIDOrDie(env, stalledTransactionInfoClazz, "layerName", "Ljava/lang/String;");
+ gStalledTransactionInfoClassInfo.bufferId =
+ GetFieldIDOrDie(env, stalledTransactionInfoClazz, "bufferId", "J");
+ gStalledTransactionInfoClassInfo.frameNumber =
+ GetFieldIDOrDie(env, stalledTransactionInfoClazz, "frameNumber", "J");
+
return err;
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index a5d287c..481a2fb 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -137,6 +137,7 @@
optional SettingProto gesture_setup_complete = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto touch_gesture_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto long_press_home_enabled = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Assist assist = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 10cf353..7d1253c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7770,8 +7770,9 @@
android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:theme="@style/Theme.NoTitleBar.Fullscreen"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
+ android:enableOnBackInvokedCallback="true"
android:icon="@drawable/platlogo"
android:process=":ui">
</activity>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a4c7dcf..74dd269 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gebruik biometrie of skermslot"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifieer dat dit jy is"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gebruik jou biometrie om voort te gaan"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Gebruik jou vingerafdruk om voort te gaan"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gebruik jou gesig om voort te gaan"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gebruik jou biometriese data of skermslot om voort te gaan"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometriese hardeware is nie beskikbaar nie"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Stawing is gekanselleer"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Vingerafdruk word nie herken nie"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Vingerafdruk word nie herken nie"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk is gestaaf"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gesig is gestaaf"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gesig is gestaaf; druk asseblief bevestig"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Laat ’n metgeselapp toe om voorgronddienste van agtergrond af te begin"</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofoon is beskikbaar"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofoon is geblokkeer"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dubbelskerm"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dubbelskerm is aan"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen is aan"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik tans albei skerms om inhoud te wys"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Toestel is te warm"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbelskerm is nie beskikbaar nie omdat jou foon tans te warm word"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is nie beskikbaar nie omdat jou foon tans te warm word"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is nie beskikbaar nie"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is nie beskikbaar nie omdat Batterybespaarder aan is. Jy kan dit in Instellings afskakel."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Gaan na Instellings"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 94a337e..64c52bb 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ባዮሜትሪክስ ወይም ማያ ገፅ መቆለፊያን ይጠቀሙ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"እርስዎን መሆንዎን ያረጋግጡ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ለመቀጠል ባዮሜትሪክዎን ይጠቀሙ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ለመቀጠል የእርስዎን መልክ ይጠቀሙ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ለመቀጠል የባዮሜትሪክ ወይም የማያ ገፅ ቁልፍዎን ይጠቀሙ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ማረጋገጥ ተሰርዟል"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"የጣት አሻራ አልታወቀም"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"የጣት አሻራ አልታወቀም"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ፊት ተረጋግጧል"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ፊት ተረጋግጧል፣ እባክዎ አረጋግጥን ይጫኑ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 75ce8da..b8a887c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -620,8 +620,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استخدام المقاييس الحيوية أو قفل الشاشة"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"إثبات هويتك"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"استخدام المقاييس الحيوية للمتابعة"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"استخدِم بصمة إصبعك للمتابعة"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"استخدِم وجهك للمتابعة"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"استخدام المقاييس الحيوية أو قفل الشاشة للمتابعة"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"معدّات المقاييس الحيوية غير متاحة."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تم إلغاء المصادقة."</string>
@@ -647,6 +645,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"لم يتمّ التعرّف على البصمة."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"لم يتمّ التعرّف على بصمة الإصبع."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"تم مصادقة بصمة الإصبع"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"تمّت مصادقة الوجه"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"تمّت مصادقة الوجه، يُرجى الضغط على \"تأكيد\"."</string>
@@ -2330,11 +2329,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"يسمح هذا الإذن للتطبيق المصاحب ببدء الخدمات التي تعمل في المقدّمة من الخلفية."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"الميكروفون متاح."</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"تم حظر الميكروفون."</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"استخدام الشاشتين"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"ميزة \"استخدام الشاشتين\" مفعّلة"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"ميزة Dual Screen مفعّلة"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"يستخدم \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" كلتا الشاشتين لعرض المحتوى."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"الجهاز ساخن للغاية"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ميزة \"استخدام الشاشتين\" غير متاحة لأن هاتفك ساخن للغاية."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ميزة Dual Screen غير متاحة لأنّ هاتفك ساخن للغاية."</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ميزة Dual Screen غير متاحة"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ميزة Dual Screen غير متاحة لأن ميزة \"توفير شحن البطارية\" مفعّلة. ويمكنك إيقاف هذا الإجراء من خلال \"الإعدادات\"."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"الانتقال إلى الإعدادات"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 60baf5d..2f9a904 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়\'মেট্ৰিক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"এইয়া আপুনিয়েই বুলি সত্যাপন কৰক"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"অব্যাহত ৰাখিবলৈ আপোনাৰ বায়\'মেট্ৰিক ব্যৱহাৰ কৰক"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"অব্যাহত ৰাখিবলৈ নিজৰ মুখাৱয়ব ব্যৱহাৰ কৰক"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"অব্যাহত ৰাখিবলৈ আপোনাৰ বায়’মেট্ৰিক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব পৰা নাই"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব পৰা নাই"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল, অনুগ্ৰহ কৰি ‘নিশ্চিত কৰক’ বুটামটো টিপক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 9bb5503..ef1c0fb 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrik məlumatlardan və ya ekran kilidindən istifadə edin"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliyinizi doğrulayın"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davam etmək üçün biometrik məlumatlarınızdan istifadə edin"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Barmaq izi ilə davam edin"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Üz ilə davam edin"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Davam etmək üçün biometrik məlumatlar və ya ekran kilidinizdən istifadə edin"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik proqram əlçatan deyil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Doğrulama ləğv edildi"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Barmaq izi tanınmır"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Barmaq izi tanınmır"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Tanımaq olmur. Barmaq izini işlədin."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmaq izi doğrulandı"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Üz doğrulandı"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Üz təsdiq edildi, təsdiq düyməsinə basın"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 33694a9..f0e08f0 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristite biometriju ili zaključavanje ekrana"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite svoj identitet"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Koristite biometrijski podatak da biste nastavili"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Nastavite pomoću otiska prsta"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Potvrdite identitet licem da biste nastavili"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Koristite biometrijski podatak ili zaključavanje ekrana da biste nastavili"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Potvrda identiteta je otkazana"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Otisak prsta nije prepoznat"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Otisak prsta nije prepoznat"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Lice nije prepoznato. Koristite otisak prsta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je potvrđeno"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je potvrđeno. Pritisnite Potvrdi"</string>
@@ -2327,11 +2326,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Dozvoljava pratećoj aplikaciji da pokrene usluge u prvom planu iz pozadine."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofon je dostupan"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon je blokiran"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dvojni ekran"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dvojni ekran je uključen"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen je uključen"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi oba ekrana za prikazivanje sadržaja"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Uređaj je previše zagrejan"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvojni ekran je nedostupan jer je telefon previše zagrejan"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen je nedostupan jer je telefon previše zagrejan"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen nije dostupan"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen nije dostupan zato što je Ušteda baterije uključena. To možete da isključite u podešavanjima."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Idi u Podešavanja"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index fe16341..f4a3ab1c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Выкарыстоўваць біяметрыю ці блакіроўку экрана"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Спраўдзіце, што гэта вы"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Каб працягнуць, скарыстайце свае біяметрычныя даныя"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Каб працягнуць, скарыстайце адбітак пальца"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Каб працягнуць, скарыстайце распазнаванне твару"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Каб працягнуць, скарыстайце біяметрычныя даныя ці сродак разблакіроўкі экрана"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біяметрычнае абсталяванне недаступнае"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аўтэнтыфікацыя скасавана"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Адбітак пальца не распазнаны"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Адбітак пальца не распазнаны"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Адбітак пальца распазнаны"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Твар распазнаны"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Твар распазнаны. Націсніце, каб пацвердзіць"</string>
@@ -2328,11 +2327,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Спадарожная праграма зможа запускаць актыўныя сэрвісы з фонавага рэжыму."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Мікрафон даступны"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Мікрафон заблакіраваны"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Двайны экран"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Уключана функцыя \"Двайны экран\""</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Уключана функцыя Dual Screen"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" выкарыстоўвае абодва экраны для паказу змесціва"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Прылада моцна нагрэлася"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функцыя \"Двайны экран\" недаступная, бо тэлефон моцна награваецца"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функцыя Dual Screen недаступная, бо тэлефон моцна награваецца"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функцыя Dual Screen недаступная"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функцыя Dual Screen недаступная, бо ўключаны рэжым энергазберажэння. Вы можаце выключыць яго ў Наладах."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Перайсці ў Налады."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2865dcf..522c4fa 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Използване на биометрични данни или опцията за заключване на екрана"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потвърдете, че сте вие"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Използвайте биометричните си данни, за да продължите"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Използвайте отпечатъка си, за да продължите"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Използвайте лицето си, за да продължите"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Използвайте биометричните си данни или опцията за заключване на екрана, за да продължите"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометричният хардуер не е налице"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Удостоверяването бе анулирано"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отпечатъкът не е разпознат"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Отпечатъкът не е разпознат"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Лицето не е разпознато. Използвайте отпечатък."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатъкът е удостоверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицето е удостоверено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицето е удостоверено. Моля, натиснете „Потвърждаване“"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index a58c081..c3482b0 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়োমেট্রিক্স অথবা স্ক্রিন লক ব্যবহার করুন"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"আপনার পরিচয় যাচাই করুন"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"চালিয়ে যেতে আপনার বায়োমেট্রিক্স ব্যবহার করুন"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"চালিয়ে যেতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"চালিয়ে যেতে আপনার ফেস ব্যবহার করুন"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"চালিয়ে যেতে আপনার বায়োমেট্রিক্স বা স্ক্রিন লক ব্যবহার করুন"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"যাচাইকরণ বাতিল হয়েছে"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ফিঙ্গারপ্রিন্ট শনাক্ত করা যায়নি"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ফিঙ্গারপ্রিন্ট শনাক্ত করা যায়নি"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ফেস যাচাই করা হয়েছে"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ফেস যাচাই করা হয়েছে, \'কনফার্ম করুন\' বোতাম প্রেস করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c74a14c..5df986a 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristi biometriju ili zaključavanje ekrana"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite identitet"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Koristite biometriju da nastavite"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Potvrdite identitet otiskom prsta da nastavite"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Potvrdite identitet licem da nastavite"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Koristite biometriju ili zaključavanje ekrana da nastavite"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija je otkazana"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Otisak prsta nije prepoznat"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Otisak prsta nije prepoznat"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je provjereno"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je provjereno, pritisnite dugme za potvrdu"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 658e8f0..4f60cac 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la teva identitat"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilitza la teva biometria per continuar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Utilitza l\'empremta digital per continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Utilitza la cara per continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilitza la biometria o el bloqueig de pantalla per continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"L\'empremta digital no s\'ha reconegut"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"L\'empremta digital no s\'ha reconegut"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"No podem detectar la cara. Usa l\'empremta digital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"L\'empremta digital s\'ha autenticat"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Cara autenticada"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Cara autenticada; prem el botó per confirmar"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b4318b4..b944831 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použít biometrii nebo zámek obrazovky"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že jste to vy"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Pokračujte biometrickým ověřením"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Pokračujte přiložením prstu"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Pokračujte ověřením obličeje"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Pokračujte ověřením pomocí biometrických údajů nebo zámku obrazovky"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardware není k dispozici"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ověření bylo zrušeno"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Otisk prstu nebyl rozpoznán"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Otisk prstu nebyl rozpoznán"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisk byl ověřen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Obličej byl ověřen"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Obličej byl ověřen, stiskněte tlačítko pro potvrzení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2b55cba..41048c7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Brug biometri eller skærmlås"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verificer, at det er dig"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Brug dine biometriske data for at fortsætte"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Brug dit fingeraftryk for at fortsætte"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Brug dit ansigt for at fortsætte"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Brug dine biometriske data eller din skærmlås for at fortsætte"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk hardware er ikke tilgængelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Godkendelsen blev annulleret"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingeraftrykket blev ikke genkendt"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingeraftrykket blev ikke genkendt"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeraftrykket blev godkendt"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansigtet er godkendt"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansigtet er godkendt. Tryk på Bekræft."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 350f2d7..82cf412 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrisches Verfahren oder Displaysperre verwenden"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Deine Identität bestätigen"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Mithilfe eines biometrischen Verfahrens fortfahren"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Fingerabdruck verwenden, um fortzufahren"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gesichtserkennung verwenden, um fortzufahren"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Verwende deine biometrischen Daten oder deine Display-Entsperrmethode, um fortzufahren"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische Hardware nicht verfügbar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentifizierung abgebrochen"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerabdruck nicht erkannt"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerabdruck nicht erkannt"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerabdruck wurde authentifiziert"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gesicht authentifiziert"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gesicht authentifiziert, bitte bestätigen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 71c9f22..430c577 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Χρήση βιομετρικών ή κλειδώματος οθόνης"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Επαλήθευση ταυτότητας"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Χρησιμοποιήστε βιομετρικά για να συνεχίσετε"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Χρησιμοποιήστε το δακτυλικό σας αποτύπωμα για να συνεχίσετε"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Χρησιμοποιήστε το πρόσωπό σας για να συνεχίσετε"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Χρήση βιομετρικών στοιχείων ή κλειδώματος οθόνης για συνέχεια"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Δεν είναι δυνατή η αναγνώριση του δακτυλικού αποτυπώματος"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Δεν είναι δυνατή η αναγνώριση του δακτυλικού αποτυπώματος"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Έγινε έλεγχος ταυτότητας προσώπου, πατήστε \"Επιβεβαίωση\""</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index d8ef0c0..30ca510 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use your fingerprint to continue"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use your face to continue"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use your biometric or screen lock to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerprint not recognised"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index b64c2e2..3231167 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify it’s you"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use your fingerprint to continue"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use your face to continue"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use your biometric or screen lock to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication canceled"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognized"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerprint not recognized"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Can’t recognize face. Use fingerprint instead."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated, please press confirm"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 09e33a7..03a1bd1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use your fingerprint to continue"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use your face to continue"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use your biometric or screen lock to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerprint not recognised"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index d52f41f..c82001e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use your fingerprint to continue"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use your face to continue"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use your biometric or screen lock to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerprint not recognised"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 6218741..68c325b 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify it’s you"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use your fingerprint to continue"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use your face to continue"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use your biometric or screen lock to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication canceled"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognized"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingerprint not recognized"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Can’t recognize face. Use fingerprint instead."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated, please press confirm"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 55c2ddb..2c0adce 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar datos biométricos o bloqueo de pantalla"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Comprueba que eres tú"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa tus datos biométricos para continuar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Usa tu huella dactilar para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Usa el rostro para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Usa tus datos biométricos o bloqueo de pantalla para continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"No hay hardware biométrico disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Se canceló la autenticación"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"No se reconoció la huella dactilar"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"No se reconoció la huella dactilar"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"No se reconoce el rostro. Usa la huella dactilar."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella dactilar"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Se autenticó el rostro"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Se autenticó el rostro; presiona Confirmar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 39f711b..ed789a1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometría o bloqueo de pantalla"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que eres tú"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa tu biometría para continuar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Usa la huella digital para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Usa la cara para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Usa la biometría o tu bloqueo de pantalla para continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticación cancelada"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Huella digital no reconocida"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Huella digital no reconocida"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"No se reconoce la cara. Usa la huella digital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se ha autenticado la huella digital"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Cara autenticada"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Se ha autenticado la cara, pulsa para confirmar"</string>
@@ -1374,7 +1373,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar depuración USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2a550eb..c25ecb6 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biomeetria või ekraaniluku kasutamine"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Kinnitage oma isik"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Jätkamiseks kasutage biomeetriat"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Jätkamiseks kasutage oma sõrmejälge"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Jätkamiseks kasutage oma nägu"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Jätkamiseks kasutage oma biomeetrilisi andmeid või ekraanilukku"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biomeetriline riistvara ei ole saadaval"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentimine tühistati"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Sõrmejälge ei tuvastatud"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Sõrmejälge ei tuvastatud"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sõrmejälg autenditi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Nägu on autenditud"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Nägu on autenditud, vajutage käsku Kinnita"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 9364179..c3a8c43 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Erabili sistema biometrikoak edo pantailaren blokeoa"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Egiaztatu zeu zarela"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Aurrera egiteko, erabili sistema biometrikoak"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Aurrera egiteko, erabili hatz-marka"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Aurrera egiteko, erabili aurpegia"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Aurrera egiteko, erabili sistema biometrikoak edo pantailaren blokeoa"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrikoa ez dago erabilgarri"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Utzi da autentifikazioa"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Ez da ezagutu hatz-marka"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Ez da ezagutu hatz-marka"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Ezin da hauteman aurpegia. Erabili hatz-marka."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentifikatu da hatz-marka"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Autentifikatu da aurpegia"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Autentifikatu da aurpegia; sakatu Berretsi"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Aurreko planoko zerbitzuak atzeko planotik abiarazteko baimena ematen die aplikazio osagarriei."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Erabilgarri dago mikrofonoa"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Blokeatuta dago mikrofonoa"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Bi pantailako modua"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Bi pantailako modua aktibatuta dago"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen aktibatuta dago"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> bi pantailak erabiltzen ari da edukia erakusteko"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Gailua beroegi dago"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Bi pantailako modua ez dago erabilgarri telefonoa berotzen ari delako"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen ez dago erabilgarri telefonoa berotzen ari delako"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ez dago erabilgarri"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ez dago erabilgarri, bateria-aurreztailea aktibatuta dagoelako. Aukera hori desaktibatzeko, joan ezarpenetara."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Joan Ezarpenak atalera"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 74ae4f2..67ae35d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از زیستسنجشی یا قفل صفحه"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شمایید"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"برای ادامه، از زیستسنجشی استفاده کنید"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"برای ادامه، از اثر انگشتتان استفاده کنید"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"برای ادامه، از چهرهتان استفاده کنید"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"برای ادامه، از زیستسنجشی یا قفل صفحه استفاده کنید"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"سختافزار زیستسنجی دردسترس نیست"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"اصالتسنجی لغو شد"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"اثر انگشت تشخیص داده نشد"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"اثر انگشت تشخیص داده نشد"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"اثر انگشت اصالتسنجی شد"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"چهره اصالتسنجی شد"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چهره اصالتسنجی شد، لطفاً تأیید را فشار دهید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3671c8c..c47f7ba 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Käytä biometriikkaa tai näytön lukitusta"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Vahvista henkilöllisyytesi"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Jatka käyttämällä biometriikkaa"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Jatka sormenjäljen avulla"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Jatka kasvojen avulla"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Jatka biometriikan tai näytön lukituksen avulla"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinen laitteisto ei käytettävissä"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Todennus peruutettu"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Sormenjälkeä ei tunnistettu"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Sormenjälkeä ei tunnistettu"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sormenjälki tunnistettu"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Kasvot tunnistettu"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Kasvot tunnistettu, valitse Vahvista"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a961f6a..be6687c 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser les données biométriques ou le verrouillage de l\'écran"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez que c\'est vous"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilisez votre méthode d\'authentification biométrique pour continuer"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Utilisez votre empreinte digitale pour continuer"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Utilisez votre visage pour continuer"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilisez vos données biométriques ou le verrouillage de l\'écran pour continuer"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Empreinte digitale non reconnue"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Empreinte digitale non reconnue"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Visage authentifié"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Visage authentifié, veuillez appuyer sur le bouton Confirmer"</string>
@@ -2327,11 +2326,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Permet à une application compagnon en arrière-plan de lancer des services d\'avant-plan."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Le microphone est accessible"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Le microphone est bloqué"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Double écran"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Le double écran est activé"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen activé"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise les deux écrans pour afficher le contenu"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"L\'appareil est trop chaud"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Le double écran n\'est pas accessible, car votre téléphone est trop chaud"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen n\'est pas accessible, car votre téléphone est trop chaud"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"La fonctionnalité Dual Screen n\'est pas accessible"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"La fonctionnalité Dual Screen n\'est pas accessible, car l\'économiseur de pile est activé. Vous pouvez désactiver cette option dans les paramètres."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Accéder aux paramètres"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a12df79..4f6d262 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser la biométrie ou le verrouillage de l\'écran"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez votre identité"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilisez la biométrie pour continuer"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Utilisez votre empreinte digitale pour continuer"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Utilisez la reconnaissance faciale pour continuer"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilisez la biométrie ou le verrouillage de l\'écran pour continuer"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Empreinte digitale non reconnue"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Empreinte digitale non reconnue"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Visage non reconnu. Utilisez votre empreinte."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Visage authentifié"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Visage authentifié, veuillez appuyer sur \"Confirmer\""</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index e157933..9dd72cc 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utilizar desbloqueo biométrico ou credencial do dispositivo"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que es ti"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Para continuar, utiliza o desbloqueo biométrico"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Usa a impresión dixital para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Usa o recoñecemento facial para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Para continuar, utiliza o desbloqueo biométrico ou o bloqueo de pantalla"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"O hardware biométrico non está dispoñible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Cancelouse a autenticación"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Non se recoñeceu a impresión dixital"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Non se recoñeceu a impresión dixital"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autenticouse a impresión dixital"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Autenticouse a cara"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Autenticouse a cara, preme Confirmar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1fcdc76..e79adb9 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"બાયોમેટ્રિક્સ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"તે તમે જ છો એ ચકાસો"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"આગળ વધવા માટે બાયોમેટ્રિકનો ઉપયોગ કરો"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ચાલુ રાખવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ચાલુ રાખવા માટે તમારા ચહેરાનો ઉપયોગ કરો"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ચાલુ રાખવા માટે તમારા બાયોમેટ્રિક ડેટા અથવા સ્ક્રીન લૉક સુવિધાનો ઉપયોગ કરો"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"પ્રમાણીકરણ રદ કર્યું"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ફિંગરપ્રિન્ટ ઓળખી શકાઈ નથી"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ફિંગરપ્રિન્ટ ઓળખી શકાઈ નથી"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ચહેરા પ્રમાણિત"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ચહેરા પ્રમાણિત, કૃપા કરીને કન્ફર્મ કરો"</string>
@@ -2330,9 +2329,9 @@
<string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen ચાલુ છે"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"કન્ટેન્ટ બતાવવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> બન્ને ડિસ્પ્લેનો ઉપયોગ કરી રહી છે"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ડિવાઇસ ખૂબ જ ગરમ છે"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે કારણ કે તમારો ફોન ખૂબ જ ગરમ થઈ રહ્યો છે"</string>
- <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે"</string>
- <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"બૅટરી સેવર ચાલુ હોવાને કારણે ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે. તમે સેટિંગમાં જઈને આને બંધ કરી શકો છો."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen ઉપલબ્ધ નથી કારણ કે તમારો ફોન ખૂબ જ ગરમ થઈ રહ્યો છે"</string>
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ઉપલબ્ધ નથી"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"બૅટરી સેવર ચાલુ હોવાને કારણે Dual Screen ઉપલબ્ધ નથી. તમે સેટિંગમાં જઈને આને બંધ કરી શકો છો."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"સેટિંગ પર જાઓ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"બંધ કરો"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>ની ગોઠવણી કરવામાં આવી છે"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index ec45501..fbec97e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"अपनी पहचान की पुष्टि करें"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"जारी रखने के लिए, बायोमेट्रिक्स इस्तेमाल करें"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"जारी रखने के लिए, अपने फ़िंगरप्रिंट की मदद से पहचान की पुष्टि करें"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"जारी रखने के लिए, अपने चेहरा की मदद से पहचान की पुष्टि करें"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"जारी रखने के लिए, बायोमेट्रिक या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द किया गया"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"फ़िंगरप्रिंट की पहचान नहीं हो पाई"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फ़िंगरप्रिंट की पहचान नहीं हो पाई"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरे की पहचान की गई"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 3c29d7b..d9b84f1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Upotreba biometrijske autentifikacije ili zaključavanja zaslona"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite da ste to vi"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Upotrijebite svoju biometrijsku autentifikaciju da biste nastavili"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Za nastavak upotrijebite otisak prsta"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Za nastavak se identificirajte licem"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Za nastavak se identificirajte biometrijski ili vjerodajnicom zaključavanja zaslona"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija otkazana"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Otisak prsta nije prepoznat"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Otisak prsta nije prepoznat"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentificirano otiskom prsta"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je autentificirano"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je autentificirano, pritisnite Potvrdi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index c96d05f..92d7727 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"A folytatás biometriai feloldással vagy képernyőzárral lehetséges"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Igazolja, hogy Ön az"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"A folytatás biometriai feloldással lehetséges"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"A folytatáshoz használja ujjlenyomatát"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"A folytatáshoz használja az arcalapú feloldást"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"A folytatás biometriai feloldással vagy a képernyőzár feloldásával lehetséges"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrikus hardver nem áll rendelkezésre"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hitelesítés megszakítva"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Az ujjlenyomat nem ismerhető fel"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Az ujjlenyomat nem ismerhető fel"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Ujjlenyomat hitelesítve"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Arc hitelesítve"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Arc hitelesítve; nyomja meg a Megerősítés lehetőséget"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a257926..94381a7 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Օգտագործել կենսաչափական համակարգեր կամ էկրանի կողպում"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Հաստատեք ձեր ինքնությունը"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Շարունակելու համար օգտագործեք կենսաչափական համակարգեր"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Շարունակելու համար օգտագործեք ձեր մատնահետքը"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Շարունակելու համար օգտագործեք դեմքով իսկորոշումը"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Շարունակելու համար օգտագործեք ձեր կենսաչափական տվյալները կամ էկրանի կողպումը"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Կենսաչափական սարքը հասանելի չէ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Նույնականացումը չեղարկվեց"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Մատնահետքը չի ճանաչվել"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Մատնահետքը չի ճանաչվել"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Մատնահետքը նույնականացվեց"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Դեմքը ճանաչվեց"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Դեմքը ճանաչվեց: Սեղմեք «Հաստատել»:"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Թույլատրում է ուղեկցող հավելվածին ակտիվ ծառայություններ գործարկել ֆոնային ռեժիմից։"</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Խոսափողը հասանելի է"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Խոսափողն արգելափակված է"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Կրկնակի էկրան"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Կրկնակի էկրանը միացված է"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen-ը միացված է"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն օգտագործում է երկու էկրանները"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Սարքը գերտաքացել է"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Կրկնակի էկրանն անհասանելի է, քանի որ ձեր հեռախոսը գերտաքանում է"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen-ն անհասանելի է, քանի որ ձեր հեռախոսը գերտաքանում է"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen-ը հասանելի չէ"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen-ն անհասանելի է, քանի որ Մարտկոցի տնտեսումը միացված է։ Դուք կարող եք անջատել այս գործառույթը Կարգավորումներում։"</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Անցնել Կարգավորումներ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 84fcd20..7ec0787 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci layar"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi bahwa ini memang Anda"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gunakan biometrik untuk melanjutkan"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Gunakan sidik jari untuk melanjutkan"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gunakan wajah untuk melanjutkan"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gunakan biometrik atau kunci layar untuk melanjutkan"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentikasi dibatalkan"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Sidik jari tidak dikenali"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Sidik jari tidak dikenali"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sidik jari diautentikasi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Wajah diautentikasi"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Wajah diautentikasi, silakan tekan konfirmasi"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Mengizinkan aplikasi pendamping memulai layanan latar depan dari latar belakang."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofon tersedia"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon diblokir"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Layar ganda"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
<string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen aktif"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggunakan kedua layar untuk menampilkan konten"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Suhu perangkat terlalu panas"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Layar ganda tidak tersedia karena suhu ponsel terlalu panas"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen tidak tersedia karena suhu ponsel terlalu panas"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen tidak tersedia"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen tidak tersedia karena Penghemat Baterai aktif. Anda dapat menonaktifkannya di Setelan."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Buka Setelan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 20c56ee..1c5738d 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -296,9 +296,9 @@
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"Örugg stilling"</string>
<string name="android_system_label" msgid="5974767339591067210">"Android kerfið"</string>
- <string name="user_owner_label" msgid="8628726904184471211">"Skipta yfir í eigið snið"</string>
+ <string name="user_owner_label" msgid="8628726904184471211">"Skipta yfir í einkasnið"</string>
<string name="managed_profile_label" msgid="7316778766973512382">"Skipta yfir í vinnusnið"</string>
- <string name="user_owner_app_label" msgid="1553595155465750298">"Skipta yfir í eigið snið <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="user_owner_app_label" msgid="1553595155465750298">"Skipta yfir í einkasnið <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="managed_profile_app_label" msgid="367401088383965725">"Skipta yfir í vinnusnið <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="permgrouplab_contacts" msgid="4254143639307316920">"Tengiliðir"</string>
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"fá aðgang að tengiliðunum þínum"</string>
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Nota lífkenni eða skjálás"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Staðfestu hver þú ert"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Notaðu lífkenni til að halda áfram"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Notaðu fingrafarið til að halda áfram"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Notaðu andlitið til að halda áfram"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Notaðu lífkenni eða skjálás til að halda áfram"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Lífkennavélbúnaður ekki tiltækur"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hætt við auðkenningu"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingrafar þekkist ekki"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingrafar þekkist ekki"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingrafar staðfest"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Andlit staðfest"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Andlit staðfest, ýttu til að staðfesta"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2ea9089..d932fcc 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usa la biometria o il blocco schermo"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la tua identità"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa la biometria per continuare"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Utilizza la tua impronta per continuare"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Usa il tuo volto per continuare"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Per continuare devi usare i tuoi dati biometrici o il tuo blocco schermo"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrico non disponibile"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticazione annullata"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Impronta non riconosciuta"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Impronta non riconosciuta"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impronta autenticata"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Volto autenticato"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Volto autenticato, premi Conferma"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9944608..33a2ada 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"שימוש במידע ביומטרי בנעילת מסך"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"אימות הזהות שלך"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"יש להשתמש במידע ביומטרי כדי להמשיך"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"צריך להשתמש בטביעת האצבע כדי להמשיך"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"צריך להשתמש בזיהוי הפנים כדי להמשיך"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"יש להשתמש במידע הביומטרי או בנעילת המסך כדי להמשיך"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"חומרה ביומטרית לא זמינה"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"האימות בוטל"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"טביעת האצבע לא זוהתה"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"טביעת האצבע לא זוהתה"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"טביעת האצבע אומתה"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"זיהוי הפנים בוצע"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"זיהוי הפנים בוצע. יש ללחוץ על אישור"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 46e29cf..b5a9363 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"生体認証または画面ロックの使用"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"本人確認"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"続行するには生体認証を使用してください"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"続行するには指紋認証を使用してください"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"続行するには顔認証を使用してください"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"続行するには、生体認証または画面ロックを使用してください"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生体認証ハードウェアが利用できません"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"認証をキャンセルしました"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"指紋を認識できません"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"指紋を認識できません"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"顔を認識できません。指紋認証を使用してください。"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"顔を認証しました"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"顔を認証しました。[確認] を押してください"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 9276dd6..4c4a521 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"გამოიყენეთ ბიომეტრიული სისტემა ან ეკრანის დაბლოკვა"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"დაადასტურეთ ვინაობა"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"გასაგრძელებლად გამოიყენეთ თქვენი ბიომეტრიული მონაცემები"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"გასაგრძელებლად გამოიყენეთ სახის ამოცნობა"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"გასაგრძელებლად გამოიყენეთ თქვენი ბიომეტრიული მონაცემები ან ეკრანის განბლოკვის ნიმუში"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ბიომეტრიული აპარატურა მიუწვდომელია"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ავტორიზაცია გაუქმდა"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"თითის ანაბეჭდის ამოცნობა ვერ მოხერხდა"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"თითის ანაბეჭდის ამოცნობა ვერ მოხერხდა"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"თითის ანაბეჭდი ავტორიზებულია"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"სახე ავტორიზებულია"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"სახე ავტორიზებულია, დააჭირეთ დადასტურებას"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 830754c..33de73c 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометриканы немесе экран құлпын пайдалану"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Бұл сіз екеніңізді растаңыз"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Жалғастыру үшін биометрикаңызды пайдаланыңыз."</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Жалғастыру үшін бетті анықтау функциясын пайдаланыңыз."</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Жалғастыру үшін биометриканы немесе экран құлпын пайдаланыңыз."</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалық жабдық жоқ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификациядан бас тартылды."</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Саусақ ізі танылмады."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Саусақ ізі танылмады."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Саусақ ізі аутентификацияланды"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Бет танылды"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Бет танылды, \"Растау\" түймесін басыңыз"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Қосымша қолданбаға экрандық режимдегі қызметтерді фоннан іске қосуға рұқсат беріледі."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон қолжетімді."</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон блокталған."</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Қос экран"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Қос экран функциясы қосулы"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen функциясы қосулы"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы контентті көрсету үшін екі дисплейді де пайдаланады."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Құрылғы қатты қызып кетті."</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Қос экран функциясы істемейді, себебі телефон қатты қызып кетеді."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen функциясы істемейді, себебі телефон қатты қызып кетеді."</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen қолжетімсіз"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Батареяны үнемдеу режимі қосулы болғандықтан, Dual Screen қолжетімсіз. Мұны параметрлерден өшіруге болады."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Параметрлерге өту"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4843de3..347276d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ប្រើជីវមាត្រ ឬការចាក់សោអេក្រង់"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ផ្ទៀងផ្ទាត់ថាជាអ្នក"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ប្រើជីវមាត្ររបស់អ្នក ដើម្បីបន្ត"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ប្រើស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ប្រើមុខរបស់អ្នក ដើម្បីបន្ត"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ប្រើការចាក់សោអេក្រង់ ឬជីវមាត្ររបស់អ្នក ដើម្បីបន្ត"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"មិនអាចប្រើឧបករណ៍ស្កេនស្នាមម្រាមដៃបានទេ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"មិនស្គាល់ស្នាមម្រាមដៃទេ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"មិនស្គាល់ស្នាមម្រាមដៃទេ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"បានផ្ទៀងផ្ទាត់ស្នាមម្រាមដៃ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"បានផ្ទៀងផ្ទាត់មុខ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"បានផ្ទៀងផ្ទាត់មុខ សូមចុចបញ្ជាក់"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 2b46233..5a3d0e6 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ಇದು ನೀವೇ ಎಂದು ಪರಿಶೀಲಿಸಿ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಬಯೋಮೆಟ್ರಿಕ್ ಬಳಸಿ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖವನ್ನು ಬಳಸಿ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಬಯೋಮೆಟ್ರಿಕ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ, ದೃಢೀಕರಣವನ್ನು ಒತ್ತಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 496f2f2..2460f96 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"생체 인식 또는 화면 잠금을 사용"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"본인 확인"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"생체 인식을 사용하여 계속하세요"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"계속하려면 지문을 인증하세요"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"계속하려면 얼굴로 인증하세요"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"계속하려면 생체 인식이나 화면 잠금을 사용하세요"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"생체 인식 하드웨어를 사용할 수 없음"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"인증이 취소되었습니다."</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"지문이 인식되지 않았습니다."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"지문을 인식할 수 없습니다."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"지문이 인증됨"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"얼굴이 인증되었습니다"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"얼굴이 인증되었습니다. 확인을 누르세요"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index fa3105f..c11b9ccf 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометрикалык жөндөөнү же экрандын кулпусун колдонуу"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Улантуу үчүн биометрикалык жөндөөнү колдонуу"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Улантуу үчүн манжаңызды сканерге тийгизиңиз"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Улантуу үчүн жүзүңүздү көрсөтүңүз"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Улантуу үчүн биометрикалык маалыматты же экрандын кулпусун колдонуңуз"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Манжа изи таанылган жок"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Манжа изи таанылган жок"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Манжа изи текшерилди"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Жүздүн аныктыгы текшерилди"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Жүздүн аныктыгы текшерилди, эми \"Ырастоону\" басыңыз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 478228b..2d5bdeb 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ໃຊ້ລະບົບຊີວະມິຕິ ຫຼື ການລັອກໜ້າຈໍ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ຢັ້ງຢືນວ່າແມ່ນທ່ານ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ໃຊ້ລະບົບຊີວະມິຕິຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ໃຊ້ລາຍນິ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ໃຊ້ໃບໜ້າຂອງທ່ານເພື່ອສືບຕໍ່"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ໃຊ້ລະບົບຊີວະມິຕິ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ບໍ່ຮູ້ຈັກລາຍນິ້ວມື"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ບໍ່ຮູ້ຈັກລາຍນິ້ວມື"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ, ກະລຸນາກົດຢືນຢັນ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 2529975..b61ff0c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Naudoti biometrinius duomenis arba ekrano užraktą"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Patvirtinkite, kad tai jūs"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Norėdami tęsti, naudokite biometrinius duomenis"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Jei norite tęsti, naudokite piršto atspaudą"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Jei norite tęsti, naudokite veido atpažinimo funkciją"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Jei norite tęsti, naudokite biometrinius duomenis arba ekrano užraktą"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinė aparatinė įranga nepasiekiama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikavimas atšauktas"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Piršto atspaudas neatpažintas"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Piršto atspaudas neatpažintas"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Piršto antspaudas autentifikuotas"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Veidas autentifikuotas"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Veidas autentifikuotas, paspauskite patvirtinimo mygtuką"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index e45422b..7ea3d59 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrijas vai ekrāna bloķēšanas izmantošana"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Apstipriniet, ka tas esat jūs"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Lai turpinātu, izmantojiet biometriju"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Izmantojiet pirksta nospiedumu, lai turpinātu"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Izmantojiet autorizāciju pēc sejas, lai turpinātu"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Izmantojiet biometrijas datus vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisko datu aparatūra nav pieejama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikācija ir atcelta"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Pirksta nospiedums netika atpazīts"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Pirksta nospiedums netika atpazīts"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pirksta nospiedums tika autentificēts."</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Seja autentificēta"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Seja ir autentificēta. Nospiediet pogu Apstiprināt."</string>
@@ -2327,13 +2326,13 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Ļauj palīglietotnei sākt priekšplāna pakalpojumus no fona."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofons ir pieejams."</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofons ir bloķēts."</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Divu ekrānu režīms"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Ieslēgts divu ekrānu režīms"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen režīms"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Ieslēgts Dual Screen režīms"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> satura rādīšanai izmanto abus displejus."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Ierīce ir pārāk sakarsusi"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Divu ekrānu režīms nav pieejams, jo tālrunis sāk pārāk sakarst."</string>
- <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Divu ekrānu režīms nav pieejams"</string>
- <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Divu ekrānu režīms nav pieejams, jo ir ieslēgts akumulatora enerģijas taupīšanas režīms. To var izslēgt iestatījumos."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen režīms nav pieejams, jo tālrunis sāk pārāk sakarst."</string>
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen režīms nav pieejams"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen režīms nav pieejams, jo ir ieslēgts akumulatora enerģijas taupīšanas režīms. To var izslēgt iestatījumos."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Atvērt iestatījumus"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Izslēgt"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ir konfigurēta"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 547f57f..c4af21f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користи биометрика или заклучен екран"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдете дека сте вие"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Користете ја вашата биометрика за да продолжите"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Користете го отпечатокот за да продолжите"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Користете го вашиот лик за да продолжите"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Користете ја вашата биометрика или заклучување екран за да продолжите"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрискиот хардвер е недостапен"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Проверката е откажана"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отпечатокот не е препознаен"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Отпечатокот не е препознаен"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Не се препознава ликот. Користете отпечаток."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатокот е проверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицето е проверено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицето е проверено, притиснете го копчето „Потврди“"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index f4117b3..54669fc 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ബയോമെട്രിക്സ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"തുടരാൻ ബയോമെട്രിക് ഉപയോഗിക്കുക"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"തുടരാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"തുടരാൻ നിങ്ങളുടെ മുഖം ഉപയോഗിക്കുക"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"തുടരാൻ നിങ്ങളുടെ ബയോമെട്രിക് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ബയോമെട്രിക് ഹാർഡ്വെയർ ലഭ്യമല്ല"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിഞ്ഞില്ല"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിഞ്ഞില്ല"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു, സ്ഥിരീകരിക്കുക അമർത്തുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index ce481bc..ad4830c 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометр эсвэл дэлгэцийн түгжээ ашиглах"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Өөрийгөө мөн гэдгийг баталгаажуулаарай"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Үргэлжлүүлэхийн тулд биометрээ ашиглана уу"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Үргэлжлүүлэхийн тулд хурууныхаа хээг ашиглана уу"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Үргэлжлүүлэхийн тулд царайгаа ашиглана уу"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Үргэлжлүүлэхийн тулд биометр эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрийн техник хангамж боломжгүй байна"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Нотолгоог цуцаллаа"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Хурууны хээг таньсангүй"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Хурууны хээг таньсангүй"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Хурууны хээг нотолсон"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Царайг баталгаажууллаа"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Царайг баталгаажууллаа. Баталгаажуулах товчлуурыг дарна уу"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index b49ee8a8..1b6efd8 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक किंवा स्क्रीन लॉक वापरा"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"हे तुम्हीच आहात याची पडताळणी करा"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"पुढे सुरू ठेवण्यासाठी तुमचे बायोमेट्रिक वापरा"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"पुढे सुरू ठेवण्यासाठी तुमची फिंगरप्रिंट वापरा"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा वापरा"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"पुढे सुरू ठेवण्यासाठी तुमचे बायोमेट्रिक किंवा स्क्रीन लॉक वापरा"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ऑथेंटिकेशन रद्द केले"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिंट ओळखली नाही"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिंट ओळखली नाही"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म प्रेस करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index ed11c36..13bb503 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci skrin"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Sahkan itu anda"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gunakan biometrik anda untuk meneruskan"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Gunakan cap jari anda untuk teruskan"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gunakan muka anda untuk teruskan"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gunakan biometrik atau kunci skrin anda untuk meneruskan pengesahan"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Perkakasan biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Pengesahan dibatalkan"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Cap jari tidak dikenali"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Cap jari tidak dikenali"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Tidak mengenali wajah. Gunakan cap jari."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Cap jari disahkan"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Wajah disahkan"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Wajah disahkan, sila tekan sahkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 488b79e..0650586 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ဇီဝမက်ထရစ်အချက်အလက်များ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"သင်ဖြစ်ကြောင်း အတည်ပြုပါ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ရှေ့ဆက်ရန် သင်၏ ဇီဝမက်ထရစ်အချက်အလက်ကို သုံးပါ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ရှေ့ဆက်ရန် သင့်မျက်နှာကို သုံးပါ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ရှေ့ဆက်ရန် သင်၏ ဇီဝမက်ထရစ်အချက်အလက် (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"လက်ဗွေကို မသိရှိပါ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"လက်ဗွေကို မသိရှိပါ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ၊ အတည်ပြုရန်ကို နှိပ်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 672a4f3..e157d17 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Bruk biometri eller skjermlås"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekreft at det er deg"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Bruk biometri for å fortsette"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Bruk fingeravtrykket for å fortsette"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Bruk ansiktet for å fortsette"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Bruk biometri eller skjermlåsen for å fortsette"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvare er utilgjengelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen er avbrutt"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Gjenkjenner ikke fingeravtrykket"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Gjenkjenner ikke fingeravtrykket"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrykket er godkjent"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansiktet er autentisert"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansiktet er autentisert. Trykk på Bekreft"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9a8f06d..45bb058 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स वा स्क्रिन लक प्रयोग गर्नुहोस्"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"यो व्यक्ति तपाईं नै हो भन्ने प्रमाणित गर्नुहोस्"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"जारी राख्न आफ्नो बायोमेट्रिक प्रयोग गर्नुहोस्"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"जारी राख्न आफ्नो अनुहार प्रयोग गर्नुहोस्"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"जारी राख्न आफ्नो बायोमेट्रिक वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"अनुहार प्रमाणीकरण गरियो"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"अनुहार प्रमाणीकरण गरियो, कृपया पुष्टि गर्नुहोस् थिच्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1d3d7f5..14f4919 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrische gegevens of schermvergrendeling gebruiken"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Je identiteit verifiëren"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gebruik je biometrische gegevens om door te gaan"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Gebruik je vingerafdruk om door te gaan"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gebruik je gezicht om door te gaan"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gebruik je biometrische gegevens of schermvergrendeling om door te gaan"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische hardware niet beschikbaar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Verificatie geannuleerd"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Vingerafdruk niet herkend"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Vingerafdruk niet herkend"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk geverifieerd"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gezicht geverifieerd"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gezicht geverifieerd. Druk op Bevestigen."</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Hiermee kan een bijbehorende app services op de voorgrond vanuit de achtergrond starten."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Microfoon is beschikbaar"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Microfoon is geblokkeerd"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dubbel scherm"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dubbel scherm staat aan"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen staat aan"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt beide schermen om content te tonen"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Het apparaat is te warm"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbel scherm is niet beschikbaar, omdat je telefoon te warm wordt"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is niet beschikbaar, omdat je telefoon te warm wordt"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is niet beschikbaar"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is niet beschikbaar omdat Batterijbesparing aanstaat. Je kunt dit uitzetten via Instellingen."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Naar Instellingen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 749ca69..5b333c1 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ବାୟୋମେଟ୍ରିକ୍ସ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ଏହା ଆପଣ ବୋଲି ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ବାୟୋମେଟ୍ରିକ୍ସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଫେସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ବାୟୋମେଟ୍ରିକ୍ କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ବାୟୋମେଟ୍ରିକ୍ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ଟିପଚିହ୍ନ ପ୍ରମାଣିତ ହେଲା"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି, ଦୟାକରି ସୁନିଶ୍ଚିତ ଦବାନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 570006f..c8e8d9a 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣੇ ਬਾਇਓਮੈਟ੍ਰਿਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣੇ ਚਿਹਰੇ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਬਾਇਓਮੈਟ੍ਰਿਕ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ, ਕਿਰਪਾ ਕਰਕੇ \'ਪੁਸ਼ਟੀ ਕਰੋ\' ਦਬਾਓ"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"ਸੰਬੰਧੀ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਤੋਂ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਉਪਲਬਧ ਹੈ"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"ਦੋਹਰੀ ਸਕ੍ਰੀਨ"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"ਦੋਹਰੀ ਸਕ੍ਰੀਨ ਚਾਲੂ ਹੈ"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen ਚਾਲੂ ਹੈ"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸਮੱਗਰੀ ਨੂੰ ਦਿਖਾਉਣ ਲਈ ਦੋਵੇਂ ਡਿਸਪਲੇਆਂ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ਡੀਵਾਈਸ ਬਹੁਤ ਗਰਮ ਹੈ"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ਦੋਹਰੀ ਸਕ੍ਰੀਨ ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬੰਦ ਕਰ ਸਕਦੇ ਹੋ।"</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 642b993..5f308d8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Używaj biometrii lub blokady ekranu"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potwierdź, że to Ty"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Użyj biometrii, by kontynuować"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Aby kontynuować, użyj odcisku palca"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Aby kontynuować, użyj rozpoznawania twarzy"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Aby kontynuować, użyj biometrii lub blokady ekranu"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Sprzęt biometryczny niedostępny"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Anulowano uwierzytelnianie"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Nie rozpoznano odcisku palca"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Nie rozpoznano odcisku palca"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Uwierzytelniono odciskiem palca"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Twarz rozpoznana"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Twarz rozpoznana, kliknij Potwierdź"</string>
@@ -2332,7 +2331,7 @@
<string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Włączono podwójny ekran"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> korzysta z obu wyświetlaczy, aby pokazać treści"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Urządzenie jest za ciepłe"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Podwójny ekran jest niedostępny, ponieważ telefon za bardzo się nagrzewa"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Funkcja Dual Screen jest niedostępna, ponieważ telefon za bardzo się nagrzewa"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Funkcja Dual Screen jest niedostępna"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Funkcja Dual Screen jest niedostępna, ponieważ włączono Oszczędzanie baterii. Możesz to wyłączyć w Ustawieniach."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Otwórz ustawienia"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 38eb6a1..2af7768 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use seus dados biométricos para continuar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use sua impressão digital para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use seu rosto para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use sua autenticação biométrica ou o bloqueio de tela para continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Impressão digital não reconhecida"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Impressão digital não reconhecida"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado, pressione \"Confirmar\""</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fbf2bde..42d1f6a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar a biometria ou o bloqueio de ecrã"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme a sua identidade"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilize a biometria para continuar."</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use a impressão digital para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use o rosto para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilize a biometria ou o bloqueio de ecrã para continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Impressão digital não reconhecida"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Impressão digital não reconhecida"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Impos. reconh. rosto. Utilize a impressão digital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"A impressão digital foi autenticada."</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado."</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado. Prima Confirmar."</string>
@@ -964,7 +963,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"Código PIN incorreto."</string>
<string name="keyguard_label_text" msgid="3841953694564168384">"Para desbloquear, prima Menu e, em seguida, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="6192313772955399160">"Sem rede móvel"</string>
+ <string name="lockscreen_carrier_default" msgid="6192313772955399160">"Sem dados"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"Ecrã bloqueado."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Prima Menu para desbloquear."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 38eb6a1..2af7768 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use seus dados biométricos para continuar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Use sua impressão digital para continuar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Use seu rosto para continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Use sua autenticação biométrica ou o bloqueio de tela para continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Impressão digital não reconhecida"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Impressão digital não reconhecida"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado, pressione \"Confirmar\""</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 040f478..97e66c9 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Folosește sistemele biometrice sau blocarea ecranului"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmă-ți identitatea"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Folosește sistemele biometrice pentru a continua"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Folosește amprenta pentru a continua"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Folosește-ți chipul pentru a continua"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Folosește sistemele biometrice sau blocarea ecranului pentru a continua"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometric indisponibil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentificarea a fost anulată"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Amprenta nu a fost recunoscută"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Amprenta nu a fost recunoscută"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Chipul nu a fost recunoscut. Folosește amprenta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Amprentă autentificată"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Chip autentificat"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Chip autentificat, apasă pe Confirmă"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 167f531..a1e1e03 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Использовать биометрию или блокировку экрана"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Подтвердите, что это вы"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Чтобы продолжить, используйте биометрические данные."</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Чтобы продолжить, прикоснитесь пальцем к сканеру."</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Чтобы продолжить, используйте фейсконтроль."</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Чтобы продолжить, используйте биометрию или данные для разблокировки экрана."</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрическое оборудование недоступно"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификация отменена"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отпечаток не распознан."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Отпечаток не распознан."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Не удалось распознать лицо. Используйте отпечаток."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечаток пальца проверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицо распознано"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицо распознано, нажмите кнопку \"Подтвердить\""</string>
@@ -2328,11 +2327,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Сопутствующее приложение сможет запускать активные службы из фонового режима."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон доступен."</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон заблокирован."</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Двойной экран"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Двойной экран включен"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Функция Dual Screen включена"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> использует оба экрана."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Устройство перегрелось"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двойной экран недоступен из-за перегрева телефона."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функция Dual Screen недоступна из-за перегрева телефона."</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функция Dual Screen недоступна"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функция Dual Screen недоступна, так как включен режим энергосбережения. Вы можете отключить его в настройках."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Открыть настройки"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index a544e4e..c4c0aa7 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ජෛවමිතික හෝ තිර අගුල භාවිත කරන්න"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"එය ඔබ බව තහවුරු කරන්න"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ඉදිරියට යාමට ඔබගේ ජෛවමිතික භාවිත කරන්න"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ඉදිරියට යාමට ඔබේ ඇඟිලි සලකුණ භාවිත කරන්න"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ඉදිරියට යාමට ඔබේ මුහුණ භාවිත කරන්න"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ඉදිරියට යාමට ඔබගේ ජෛවමිතික හෝ තිර අගුල භාවිත කරන්න"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"සත්යාපනය අවලංගු කළා"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ඇඟිලි සලකුණ හඳුනා නොගන්නා ලදි"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ඇඟිලි සලකුණ හඳුනා නොගන්නා ලදි"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"මුහුණ සත්යාපනය කරන ලදී"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"මුහුණ සත්යාපනය කරන ලදී, කරුණාකර තහවුරු කරන්න ඔබන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index a5c1ffc..4b31793 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použiť biometrické údaje alebo zámku obrazovky"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Overenie, že ste to vy"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Ak chcete pokračovať, použite biometrický údaj"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Pokračujte nasnímaním odtlačku prsta"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Pokračujte nasnímaním tváre"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Pokračujte použitím biometrických údajov alebo zámky obrazovky"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardvér nie je k dispozícii"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Overenie bolo zrušené"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Odtlačok prsta nebol rozpoznaný"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Odtlačok prsta nebol rozpoznaný"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Odtlačok prsta bol overený"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Tvár bola overená"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Tvár bola overená, stlačte tlačidlo potvrdenia"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4a5257a..630df53 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Uporaba biometrike ali odklepanja s poverilnico"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Preverite, da ste res vi"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Za nadaljevanje uporabite biometrični podatek."</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Za nadaljevanje uporabite prstni odtis"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Za nadaljevanje uporabite obraz"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Za nadaljevanje uporabite biometrični podatek ali odklepanje s poverilnico."</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Strojna oprema za biometrične podatke ni na voljo"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Preverjanje pristnosti je preklicano"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Prstni odtis ni prepoznan."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Prstni odtis ni prepoznan."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pristnost prstnega odtisa je preverjena"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Pristnost obraza je potrjena"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Pristnost obraza je preverjena. Pritisnite gumb »Potrdi«."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 9a1601d..7a89279 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Përdor sistemet biometrike ose kyçjen e ekranit"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiko që je ti"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Përdor sistemet e tua biometrike për të vazhduar"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Përdor gjurmën e gishtit për të vazhduar"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Përdor fytyrën tënde për të vazhduar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Përdor sistemet e tua biometrike ose kyçjen e ekranit për të vazhduar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Nuk ofrohet harduer biometrik"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Vërtetimi u anulua"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Gjurma e gishtit nuk u njoh"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Gjurma e gishtit nuk u njoh"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Gjurma e gishtit u vërtetua"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Fytyra u vërtetua"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Fytyra u vërtetua, shtyp \"Konfirmo\""</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index da005dc..27886aa 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -617,8 +617,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користите биометрију или закључавање екрана"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдите свој идентитет"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Користите биометријски податак да бисте наставили"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Наставите помоћу отиска прста"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Потврдите идентитет лицем да бисте наставили"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Користите биометријски податак или закључавање екрана да бисте наставили"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометријски хардвер није доступан"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Потврда идентитета је отказана"</string>
@@ -644,6 +642,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отисак прста није препознат"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Отисак прста није препознат"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Лице није препознато. Користите отисак прста."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отисак прста је потврђен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лице је потврђено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лице је потврђено. Притисните Потврди"</string>
@@ -2327,11 +2326,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Дозвољава пратећој апликацији да покрене услуге у првом плану из позадине."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон је доступан"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон је блокиран"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Двојни екран"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Двојни екран је укључен"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen је укључен"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи оба екрана за приказивање садржаја"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Уређај је превише загрејан"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двојни екран је недоступан јер је телефон превише загрејан"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen је недоступан јер је телефон превише загрејан"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen није доступан"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen није доступан зато што је Уштеда батерије укључена. То можете да искључите у подешавањима."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Иди у Подешавања"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8d2bdf7..fad1d52 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Använd biometrisk data eller skärmlåset"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiera din identitet"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Fortsätt med hjälp av din biometriska data"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Fortsätt med hjälp av ditt fingeravtryck"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Fortsätt med hjälp av ditt ansikte"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Fortsätt med hjälp av din biometriska data eller skärmlåset"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvara är inte tillgänglig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingeravtrycket känns inte igen"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Fingeravtrycket känns inte igen"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrycket har autentiserats"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansiktet har autentiserats"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansiktet har autentiserats. Tryck på Bekräfta"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Tillåter att en tillhörande app startar förgrundstjänster i bakgrunden."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofonen är tillgänglig"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofonen är blockerad"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dubbel skärm"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dubbel skärm är på"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen är på"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> använder båda skärmarna för att visa innehåll"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Enheten är för varm"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbel skärm kan inte användas eftersom telefonen börjar bli för varm"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen kan inte användas eftersom telefonen börjar bli för varm"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen är inte tillgängligt"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen kan inte användas eftersom battersparläget är aktiverat. Du kan inaktivera detta i inställningarna."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Öppna inställningarna"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index b6dbb40..cd6d698 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Tumia bayometriki au mbinu ya kufunga skrini"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Thibitisha kuwa ni wewe"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Tumia bayometriki yako ili uendelee"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Tumia alama ya kidole chako ili uendelee"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Tumia uso wako ili uendelee"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Tumia bayometriki au mbinu yako ya kufunga skrini ili uendelee"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maunzi ya bayometriki hayapatikani"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Imeghairi uthibitishaji"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Alama ya kidole haijatambuliwa"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Alama ya kidole haijatambuliwa"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Imethibitisha alama ya kidole"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Uso umethibitishwa"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Uso umethibitishwa, tafadhali bonyeza thibitisha"</string>
@@ -2327,12 +2326,12 @@
<string name="mic_access_on_toast" msgid="2666925317663845156">"Maikrofoni inapatikana"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Maikrofoni imezuiwa"</string>
<string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Umewasha kipengele cha hali ya skrini mbili"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen imewasha"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumia skrini zote kuonyesha maudhui"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Kifaa kina joto sana"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Kipengele cha Hali ya Skrini Mbili hakipatikani kwa sababu simu yako inapata joto sana"</string>
- <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Kipengele cha Hali ya Skrini Mbili hakipatikani"</string>
- <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Kipengele cha Hali ya Skrini Mbili hakipatikani kwa sababu kipengele cha Kiokoa Betri kimewashwa. Unaweza kuzima kipengele hiki katika Mipangilio."</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Kipengele cha Dual Screen hakipatikani kwa sababu simu yako inapata joto sana"</string>
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen haipatikani"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Kipengele cha Dual Screen hakipatikani kwa sababu Kiokoa Betri kimewashwa. Unaweza kukizima katika Mipangilio."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Nenda kwenye Mipangilio"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Zima"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> imewekewa mipangilio"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 56b3de3..518b786 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"பயோமெட்ரிக்ஸையோ திரைப் பூட்டையோ பயன்படுத்து"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"நீங்கள்தான் என உறுதிசெய்க"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"தொடர உங்கள் பயோமெட்ரிக்கைப் பயன்படுத்துங்கள்"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"தொடர்வதற்கு உங்கள் கைரேகையைப் பயன்படுத்துங்கள்"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"தொடர்வதற்கு உங்கள் முகத்தைப் பயன்படுத்துங்கள்"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"தொடர, உங்கள் பயோமெட்ரிக்கையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"அங்கீகரிப்பு ரத்தானது"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"கைரேகை அங்கீகரிக்கப்படவில்லை"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"கைரேகை அங்கீகரிக்கப்படவில்லை"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"முகம் அங்கீகரிக்கப்பட்டது"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"முகம் அங்கீகரிக்கப்பட்டது. ’உறுதிப்படுத்துக’ என்பதை அழுத்துக"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 04968d3..3cf0609c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"బయోమెట్రిక్స్ను లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ఇది మీరేనని వెరిఫై చేసుకోండి"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"కొనసాగించడానికి, మీ బయోమెట్రిక్ను ఉపయోగించండి"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"కొనసాగించడానికి మీ ముఖాన్ని ఉపయోగించండి"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"కొనసాగించడానికి మీ బయోమెట్రిక్ లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"బయోమెట్రిక్ హార్డ్వేర్ అందుబాటులో లేదు"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"వేలిముద్ర గుర్తించబడలేదు"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"వేలిముద్ర గుర్తించబడలేదు"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ముఖం ప్రమాణీకరించబడింది"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ముఖం ప్రమాణీకరించబడింది, దయచేసి ధృవీకరించును నొక్కండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 6f5bd86..f2ced77 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ใช้ข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ยืนยันว่าเป็นตัวคุณ"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ใช้ข้อมูลไบโอเมตริกเพื่อดำเนินการต่อ"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"ใช้ใบหน้าของคุณเพื่อดำเนินการต่อ"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ใช้ข้อมูลไบโอเมตริกหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ไม่รู้จักลายนิ้วมือ"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"ไม่รู้จักลายนิ้วมือ"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ตรวจสอบสิทธิ์ใบหน้าแล้ว โปรดกดยืนยัน"</string>
@@ -1402,7 +1401,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"แสดงทับแอปอื่นๆ"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"แสดงทับบนแอปอื่นๆ"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> แสดงทับแอปอื่นๆ"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> กำลังแสดงทับแอปอื่นๆ"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"หากคุณไม่ต้องการให้ <xliff:g id="NAME">%s</xliff:g> ใช้ฟีเจอร์นี้ ให้แตะเพื่อเปิดการตั้งค่าแล้วปิดฟีเจอร์"</string>
@@ -2330,7 +2329,7 @@
<string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen เปิดอยู่"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังใช้จอแสดงผลทั้งสองจอเพื่อแสดงเนื้อหา"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"อุปกรณ์ร้อนเกินไป"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"หน้าจอคู่ไม่พร้อมให้ใช้งานเนื่องจากโทรศัพท์ของคุณร้อนเกินไป"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen ไม่พร้อมให้ใช้งานเนื่องจากโทรศัพท์ของคุณร้อนเกินไป"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ใช้งานไม่ได้"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ใช้งานไม่ได้เนื่องจากเปิดโหมดประหยัดแบตเตอรี่อยู่ คุณปิดโหมดนี้ได้ในการตั้งค่า"</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"ไปที่การตั้งค่า"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b4fefee..826e2b0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gumamit ng biometrics o lock ng screen"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"I-verify na ikaw ito"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gamitin ang iyong biometric para magpatuloy"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Gamitin ang iyong fingerprint para magpatuloy"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Gamitin ang iyong mukha para magpatuloy"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gamitin ang iyong biometric o lock ng screen para magpatuloy"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Walang biometric hardware"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Nakansela ang pag-authenticate"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Hindi nakilala ang fingerprint"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Hindi nakilala ang fingerprint"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Na-authenticate ang fingerprint"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Na-authenticate ang mukha"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Na-authenticate ang mukha, pakipindot ang kumpirmahin"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4113754..3ab7339 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biyometri veya ekran kilidi kullan"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Siz olduğunuzu doğrulayın"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Devam etmek için biyometri kullanın"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Devam etmek için parmak izinizi kullanın"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Devam etmek için yüzünüzü kullanın"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Devam etmek için biyometrik kimlik bilginizi veya ekran kilidinizi kullanın"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biyometrik donanım kullanılamıyor"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Kimlik doğrulama iptal edildi"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Parmak izi tanınmadı"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Parmak izi tanınmadı"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Parmak izi kimlik doğrulaması yapıldı"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Yüz kimliği doğrulandı"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Yüz kimliği doğrulandı, lütfen onayla\'ya basın"</string>
@@ -2326,11 +2325,11 @@
<string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Tamamlayıcı uygulamanın arka plandan ön plan hizmetlerini başlatmasına izin verir."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofon kullanılabilir"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon engellenmiş"</string>
- <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Çift ekran"</string>
- <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Çift ekran açık"</string>
+ <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
+ <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen açık"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>, içeriği göstermek için her iki ekranı da kullanıyor"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Cihaz çok ısındı"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Telefonunuz çok ısındığı için Çift Ekran kullanılamıyor"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Telefonunuz çok ısındığı için Dual Screen kullanılamıyor"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen kullanılamıyor"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Pil Tasarrufu açık olduğundan Dual Screen kullanılamıyor. Bu özelliği Ayarlar\'dan kapatabilirsiniz."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Ayarlar\'a git"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 92d6748..40fca1c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -618,8 +618,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Використовувати біометрію або дані для розблокування екрана"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Підтвердьте, що це ви"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Щоб продовжити, скористайтеся біометрією"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Щоб продовжити, скористайтеся відбитком пальця"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Щоб продовжити, скористайтеся фейс-контролем"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Щоб продовжити, скористайтеся біометрією або даними для розблокування екрана"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біометричне апаратне забезпечення недоступне"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Автентифікацію скасовано"</string>
@@ -645,6 +643,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Відбиток пальця не розпізнано"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Відбиток пальця не розпізнано"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Відбиток пальця автентифіковано"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Обличчя автентифіковано"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Обличчя автентифіковано. Натисніть \"Підтвердити\""</string>
@@ -2332,7 +2331,7 @@
<string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen увімкнено"</string>
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує обидва екрани для показу контенту"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Пристрій сильно нагрівається"</string>
- <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Подвійний екран недоступний, оскільки телефон сильно нагрівається"</string>
+ <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функція Dual Screen недоступна, оскільки телефон сильно нагрівається"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функція Dual Screen недоступна"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функція Dual Screen недоступна, оскільки ввімкнено режим енергозбереження. Її можна вимкнути в налаштуваннях."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"Перейти до налаштувань"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 07a1cb80..94b1c51 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"بایو میٹرکس یا اسکرین لاک استعمال کریں"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"توثیق کریں کہ یہ آپ ہیں"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"جاری رکھنے کیلئے اپنا بایو میٹرک استعمال کریں"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"جاری رکھنے کے لیے اپنا فنگر پرنٹ استعمال کریں"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"جاری رکھنے کے لیے اپنے چہرے کا استعمال کریں"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"جاری رکھنے کے لیے اپنے بایو میٹرک اور اسکرین لاک کا استعمال کریں"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تصدیق کا عمل منسوخ ہو گیا"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"فنگر پرنٹ کی شناخت نہیں ہو سکی"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"فنگر پرنٹ کی شناخت نہیں ہو سکی"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"چہرے کی تصدیق ہو گئی"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چہرے کی تصدیق ہو گئی، براہ کرم \'تصدیق کریں\' کو دبائيں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c92a239..bf0d60d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrika yoki ekran qulfi"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Oʻzingizni taniting"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davom etish uchun biometrik tasdiqlang"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Davom etish uchun barmoq izingizdan foydalaning"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Yuz tekshiruvi bilan davom eting"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Davom etish uchun biometrika yoki ekran qulfidan foydalaning"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik sensor ishlamayapti"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikatsiya bekor qilindi"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Barmoq izi aniqlanmadi"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Barmoq izi aniqlanmadi"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Bu yuz notanish. Barmoq izi orqali urining."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmoq izi tekshirildi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Yuzingiz aniqlandi"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Yuzingiz aniqlandi, tasdiqlash uchun bosing"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 5b54104..177bf89 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Dùng dữ liệu sinh trắc học hoặc phương thức khóa màn hình"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Dùng dữ liệu sinh trắc học của bạn để tiếp tục"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Hãy dùng vân tay để tiếp tục"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Hãy dùng khuôn mặt để tiếp tục"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Dùng dữ liệu sinh trắc học của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Không nhận dạng được vân tay"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Không nhận dạng được vân tay"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Đã xác thực vân tay"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Đã xác thực khuôn mặt"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Đã xác thực khuôn mặt, vui lòng nhấn để xác nhận"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index bb5889b..b89f6b2 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -274,7 +274,7 @@
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"实体键盘"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"车载模式"</string>
- <string name="notification_channel_account" msgid="6436294521740148173">"帐号状态"</string>
+ <string name="notification_channel_account" msgid="6436294521740148173">"账号状态"</string>
<string name="notification_channel_developer" msgid="1691059964407549150">"开发者消息"</string>
<string name="notification_channel_developer_important" msgid="7197281908918789589">"重要开发者消息"</string>
<string name="notification_channel_updates" msgid="7907863984825495278">"更新"</string>
@@ -448,9 +448,9 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"允许应用发送置顶广播,这类广播在广播结束后仍会继续存在。过度使用这项功能可能会导致 Android TV 设备使用过多内存,从而降低其运行速度或稳定性。"</string>
<string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"允许该应用发送持久广播消息,此类消息在广播结束后仍会保留。过度使用可能会导致手机使用过多内存,从而降低其速度或稳定性。"</string>
<string name="permlab_readContacts" msgid="8776395111787429099">"读取联系人"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"允许该应用读取您的平板电脑上存储的联系人相关数据。应用还将有权访问您的平板电脑上已创建联系人的帐号,其中可能包括您已安装的应用所创建的帐号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
- <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"允许该应用读取您的 Android TV 设备上存储的联系人相关数据。应用还将有权访问您的 Android TV 设备上已创建联系人的帐号,其中可能包括您已安装的应用所创建的帐号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
- <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"允许该应用读取您手机上存储的联系人相关数据。应用还将有权访问您的手机上已创建联系人的帐号,其中可能包括您已安装的应用所创建的帐号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"允许该应用读取您的平板电脑上存储的联系人相关数据。应用还将有权访问您的平板电脑上已创建联系人的账号,其中可能包括您已安装的应用所创建的账号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
+ <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"允许该应用读取您的 Android TV 设备上存储的联系人相关数据。应用还将有权访问您的 Android TV 设备上已创建联系人的账号,其中可能包括您已安装的应用所创建的账号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
+ <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"允许该应用读取您手机上存储的联系人相关数据。应用还将有权访问您的手机上已创建联系人的账号,其中可能包括您已安装的应用所创建的账号。此权限允许应用保存您的联系人数据,而恶意应用可能会在您不知情的情况下分享联系人数据。"</string>
<string name="permlab_writeContacts" msgid="8919430536404830430">"修改您的通讯录"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"允许该应用修改您平板电脑上存储的联系人相关数据。此权限允许应用删除联系人数据。"</string>
<string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"允许该应用修改您的 Android TV 设备上存储的联系人相关数据。此权限允许应用删除联系人数据。"</string>
@@ -542,10 +542,10 @@
<string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"允许应用更改平板电脑的时区。"</string>
<string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"允许应用更改 Android TV 设备的时区。"</string>
<string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"允许应用更改手机的时区。"</string>
- <string name="permlab_getAccounts" msgid="5304317160463582791">"查找设备上的帐号"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"允许该应用获取平板电脑已知的帐号列表,其中可能包括由已安装的应用创建的所有帐号。"</string>
- <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"允许应用获取 Android TV 设备已知的帐号列表,其中可能包括您已安装的应用所创建的任何帐号。"</string>
- <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"允许该应用获取手机已知的帐号列表,其中可能包括由已安装的应用创建的所有帐号。"</string>
+ <string name="permlab_getAccounts" msgid="5304317160463582791">"查找设备上的账号"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"允许该应用获取平板电脑已知的账号列表,其中可能包括由已安装的应用创建的所有账号。"</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"允许应用获取 Android TV 设备已知的账号列表,其中可能包括您已安装的应用所创建的任何账号。"</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"允许该应用获取手机已知的账号列表,其中可能包括由已安装的应用创建的所有账号。"</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"查看网络连接"</string>
<string name="permdesc_accessNetworkState" msgid="4394564702881662849">"允许该应用查看网络连接的相关信息,例如存在和连接的网络。"</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"拥有完全的网络访问权限"</string>
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物识别或屏幕锁定凭据"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"验证是您本人在操作"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"使用生物识别验证身份才能继续"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"如需继续操作,请使用指纹验证身份"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"如需继续操作,请刷脸验证身份"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"使用生物识别或屏幕锁定凭据验证身份,才能继续操作"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生物识别硬件无法使用"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"身份验证已取消"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"未能识别指纹"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"未能识别指纹"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"无法识别人脸。请改用指纹。"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"已验证指纹"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"面孔已验证"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"面孔已验证,请按确认按钮"</string>
@@ -730,11 +729,11 @@
<string name="face_error_vendor_unknown" msgid="7387005932083302070">"出了点问题,请重试。"</string>
<string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"读取同步设置"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允许该应用读取某个帐号的同步设置。例如,此权限可确定“联系人”应用是否与某个帐号同步。"</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允许该应用读取某个账号的同步设置。例如,此权限可确定“联系人”应用是否与某个账号同步。"</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"启用和停用同步"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"允许该应用修改某个帐号的同步设置。例如,此权限可用于在“联系人”应用与某个帐号之间启用同步。"</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"允许该应用修改某个账号的同步设置。例如,此权限可用于在“联系人”应用与某个账号之间启用同步。"</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"读取同步统计信息"</string>
- <string name="permdesc_readSyncStats" msgid="3867809926567379434">"允许该应用读取某个帐号的同步统计信息,包括同步活动历史记录和同步数据量。"</string>
+ <string name="permdesc_readSyncStats" msgid="3867809926567379434">"允许该应用读取某个账号的同步统计信息,包括同步活动历史记录和同步数据量。"</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"读取您共享存储空间中的内容"</string>
<string name="permdesc_sdcardRead" msgid="6872973242228240382">"允许该应用读取您共享存储空间中的内容。"</string>
<string name="permlab_readMediaAudio" msgid="8723513075731763810">"从共享存储空间读取音频文件"</string>
@@ -1000,7 +999,7 @@
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"您已经<xliff:g id="NUMBER_0">%1$d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%2$d</xliff:g>秒后重试。"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的 Google 登录信息解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"您已画错解锁图案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您登录 Google 帐号来解锁 Android TV 设备。\n\n 请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"您已画错解锁图案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您登录 Google 账号来解锁 Android TV 设备。\n\n 请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的 Google 登录信息解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,平板电脑将恢复为出厂默认设置,所有用户数据都会丢失。"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"您尝试解锁 Android TV 设备失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,您的 Android TV 设备就会恢复出厂设置,而且所有用户数据都会丢失。"</string>
@@ -1010,9 +1009,9 @@
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"您已经<xliff:g id="NUMBER">%d</xliff:g>次错误地尝试解锁手机。手机现在将恢复为出厂默认设置。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g>秒后重试。"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"忘记了图案?"</string>
- <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"帐号解锁"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"账号解锁"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"图案尝试次数过多"</string>
- <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"要解除锁定,请使用您的 Google 帐号登录。"</string>
+ <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"要解除锁定,请使用您的 Google 账号登录。"</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"用户名(电子邮件)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"密码"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"登录"</string>
@@ -1480,14 +1479,14 @@
<string name="ime_action_default" msgid="8265027027659800121">"执行"</string>
<string name="dial_number_using" msgid="6060769078933953531">"拨打电话\n<xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="6200708808003692594">"创建电话号码为\n<xliff:g id="NUMBER">%s</xliff:g> 的联系人"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"以下一个或多个应用请求获得相应权限,以便在当前和以后访问您的帐号。"</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"以下一个或多个应用请求获得相应权限,以便在当前和以后访问您的账号。"</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"您是否同意此请求?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"访问权限请求"</string>
<string name="allow" msgid="6195617008611933762">"允许"</string>
<string name="deny" msgid="6632259981847676572">"拒绝"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"权限请求"</string>
- <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"应用对帐号 <xliff:g id="ACCOUNT">%s</xliff:g>\n 提出权限请求。"</string>
- <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"“<xliff:g id="APP">%1$s</xliff:g>”请求获得以下帐号的访问权限:\n<xliff:g id="ACCOUNT">%2$s</xliff:g>。"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"应用对账号 <xliff:g id="ACCOUNT">%s</xliff:g>\n 提出权限请求。"</string>
+ <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"“<xliff:g id="APP">%1$s</xliff:g>”请求获得以下账号的访问权限:\n<xliff:g id="ACCOUNT">%2$s</xliff:g>。"</string>
<string name="forward_intent_to_owner" msgid="4620359037192871015">"您目前是在工作资料之外使用此应用"</string>
<string name="forward_intent_to_work" msgid="3620262405636021151">"您目前是在工作资料内使用此应用"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"输入法"</string>
@@ -1533,13 +1532,13 @@
<string name="gpsVerifYes" msgid="3719843080744112940">"是"</string>
<string name="gpsVerifNo" msgid="1671201856091564741">"否"</string>
<string name="sync_too_many_deletes" msgid="6999440774578705300">"超出删除限制"</string>
- <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"帐号 <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> 在进行“<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>”同步时删除了 <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> 项内容。您要如何处理这些删除的内容?"</string>
+ <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"账号 <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> 在进行“<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>”同步时删除了 <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> 项内容。您要如何处理这些删除的内容?"</string>
<string name="sync_really_delete" msgid="5657871730315579051">"删除这些内容"</string>
<string name="sync_undo_deletes" msgid="5786033331266418896">"撤消删除"</string>
<string name="sync_do_nothing" msgid="4528734662446469646">"目前不进行任何操作"</string>
- <string name="choose_account_label" msgid="5557833752759831548">"选择帐号"</string>
- <string name="add_account_label" msgid="4067610644298737417">"添加帐号"</string>
- <string name="add_account_button_label" msgid="322390749416414097">"添加帐号"</string>
+ <string name="choose_account_label" msgid="5557833752759831548">"选择账号"</string>
+ <string name="add_account_label" msgid="4067610644298737417">"添加账号"</string>
+ <string name="add_account_button_label" msgid="322390749416414097">"添加账号"</string>
<string name="number_picker_increment_button" msgid="7621013714795186298">"增大"</string>
<string name="number_picker_decrement_button" msgid="5116948444762708204">"减小"</string>
<string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> 触摸并按住。"</string>
@@ -1663,13 +1662,13 @@
<string name="kg_invalid_puk" msgid="4809502818518963344">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN 码不匹配"</string>
<string name="kg_login_too_many_attempts" msgid="699292728290654121">"图案尝试次数过多"</string>
- <string name="kg_login_instructions" msgid="3619844310339066827">"要解锁,请登录您的 Google 帐号。"</string>
+ <string name="kg_login_instructions" msgid="3619844310339066827">"要解锁,请登录您的 Google 账号。"</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"用户名(电子邮件地址)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"密码"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"登录"</string>
<string name="kg_login_invalid_input" msgid="8292367491901220210">"用户名或密码无效。"</string>
<string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
- <string name="kg_login_checking_password" msgid="4676010303243317253">"正在检查帐号…"</string>
+ <string name="kg_login_checking_password" msgid="4676010303243317253">"正在检查账号…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"您已经<xliff:g id="NUMBER_0">%1$d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%2$d</xliff:g>秒后重试。"</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
@@ -1679,9 +1678,9 @@
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"您已经<xliff:g id="NUMBER">%d</xliff:g>次错误地尝试解锁平板电脑。平板电脑现在将恢复为出厂默认设置。"</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"您尝试解锁 Android TV 设备失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Android TV 设备现在将恢复出厂设置。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"您已经<xliff:g id="NUMBER">%d</xliff:g>次错误地尝试解锁手机。手机现在将恢复为出厂默认设置。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"您已画错解锁图案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用电子邮件帐号解锁 Android TV 设备。\n\n 请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件账号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"您已画错解锁图案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用电子邮件账号解锁 Android TV 设备。\n\n 请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件账号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"删除"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
@@ -1731,7 +1730,7 @@
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"放大功能"</string>
<string name="user_switched" msgid="7249833311585228097">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="1912993630661332336">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
- <string name="user_logging_out_message" msgid="7216437629179710359">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出帐号…"</string>
+ <string name="user_logging_out_message" msgid="7216437629179710359">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出账号…"</string>
<string name="owner_name" msgid="8713560351570795743">"机主"</string>
<string name="guest_name" msgid="8502103277839834324">"访客"</string>
<string name="error_message_title" msgid="4082495589294631966">"错误"</string>
@@ -1936,7 +1935,7 @@
<string name="importance_from_user" msgid="2782756722448800447">"这些通知的重要程度由您来设置。"</string>
<string name="importance_from_person" msgid="4235804979664465383">"这条通知涉及特定的人,因此被归为重要通知。"</string>
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"自定义应用通知"</string>
- <string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
+ <string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此账号)创建新用户吗?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
<string name="supervised_user_creation_label" msgid="6884904353827427515">"添加受监管用户"</string>
<string name="language_selection_title" msgid="52674936078683285">"添加语言"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 2537e08..819106a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物識別或螢幕鎖定"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證是你本人"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"如要繼續操作,請使用使用生物識別驗證身分"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"如要繼續操作,請使用你的指紋驗證身分"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"如要繼續操作,請使用你的面孔驗證身分"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"請使用生物識別或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物識別硬件"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"無法辨識指紋"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"無法辨識指紋"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"無法辨識面孔,請改用指紋完成驗證。"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"驗證咗指紋"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"面孔已經驗證"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"面孔已經驗證,請㩒一下 [確認]"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 4e0d189..746be60 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物特徵辨識或螢幕鎖定功能"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證你的身分"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"如要繼續操作,請使用生物特徵辨識功能驗證身分"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"如要繼續操作,請使用指紋驗證身分"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"如要繼續操作,請使用臉孔驗證身分"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"請使用生物特徵辨識或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物特徵辨識硬體"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"指紋辨識失敗"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"指紋辨識失敗"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"無法辨識臉孔,請改用指紋完成驗證。"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋驗證成功"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"臉孔驗證成功"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"臉孔驗證成功,請按下 [確認] 按鈕"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 171432b..9908707 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -616,8 +616,6 @@
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Sebenzisa i-biometrics noma ukukhiya isikrini"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Qinisekisa ukuthi nguwe"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Sebenzisa i-biometric yakho ukuze uqhubeke"</string>
- <string name="biometric_dialog_fingerprint_subtitle" msgid="2520227942533751342">"Sebenzisa isigxivizo sakho somunwe ukuze uqhubeke"</string>
- <string name="biometric_dialog_face_subtitle" msgid="5269284162191087084">"Sebenzisa ubuso bakho ukuze uqhubeke"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Sebenzisa i-biometric noma ukukhiya isikrini ukuze uqhubeke"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"I-Biometric hardware ayitholakali"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ukufakazela ubuqiniso kukhanseliwe"</string>
@@ -643,6 +641,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Isigxivizo somunwe asaziwa"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Isigxivizo somunwe asaziwa"</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6226091888364083421">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Izigxivizo zeminwe zigunyaziwe"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ubuso bufakazelwe ubuqiniso"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ukuqinisekiswa kobuso, sicela ucindezele okuthi qinisekisa"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f7bc53..735e590 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2465,7 +2465,7 @@
duration of the vector animation automatically. -->
<attr name="windowSplashScreenAnimationDuration" format="integer"/>
- <!-- Place an drawable image in the bottom of the starting window, it can be used to
+ <!-- Place a drawable image in the bottom of the starting window. The image can be used to
represent the branding of the application. -->
<attr name="windowSplashScreenBrandingImage" format="reference"/>
<!-- Set a background behind the splash screen icon. This is useful if there is not enough
@@ -3245,7 +3245,7 @@
<!-- Specifies the id of a view for which this view serves as a label for
accessibility purposes. For example, a TextView before an EditText in
- the UI usually specifies what infomation is contained in the EditText.
+ the UI usually specifies what information is contained in the EditText.
Hence, the TextView is a label for the EditText. -->
<attr name="labelFor" format="reference" />
@@ -6787,7 +6787,7 @@
edges of a bitmap when rotated. Default value is false. -->
<attr name="antialias" format="boolean" />
<!-- Enables or disables bitmap filtering. Filtering is used when the bitmap is
- shrunk or stretched to smooth its apperance. Default value is true. -->
+ shrunk or stretched to smooth its appearance. Default value is true. -->
<attr name="filter" format="boolean" />
<!-- Enables or disables dithering of the bitmap if the bitmap does not have the
same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b7d088b..95f1493 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -634,7 +634,7 @@
able to return to it. -->
<attr name="noHistory" format="boolean" />
- <!-- Specify whether an acitivty's task state should always be maintained
+ <!-- Specify whether an activity's task state should always be maintained
by the system, or if it is allowed to reset the task to its initial
state in certain situations.
@@ -731,15 +731,17 @@
This is equivalent to calling {@link android.app.Activity#setVrModeEnabled} with the
the given component name within the Activity that this attribute is set for.
Declaring this will prevent the system from leaving VR mode during an Activity
- transtion from one VR activity to another. -->
+ transition from one VR activity to another. -->
<attr name="enableVrMode" format="string" />
- <!-- Flag allowing the activity to specify which screen rotation animation
- it desires. Valid values are "rotate", "crossfade", and "jumpcut"
- as described in {@link android.view.WindowManager.LayoutParams#rotationAnimation}.
- Specifying your Rotation animation in the WindowManager.LayoutParams
- may be racy with app startup and updattransitions occuring during application startup and thusly
- the manifest attribute is preferred.
+ <!-- Flag that specifies the activity's preferred screen rotation animation.
+ Valid values are "rotate", "crossfade", "jumpcut", and "seamless" as
+ described in
+ {@link android.view.WindowManager.LayoutParams#rotationAnimation}.
+ Specifying your rotation animation in
+ <code>WindowManager.LayoutParams</code> may be racy with app startup
+ and update transitions that occur during application startup; and so,
+ specify the animation in the manifest attribute.
-->
<attr name="rotationAnimation">
<flag name="rotate" value= "0" />
@@ -830,7 +832,7 @@
<enum name="singleInstance" value="3" />
<!-- The activity can only be running as the root activity of the task, the first activity
that created the task, and therefore there will only be one instance of this activity
- in a task. In constrast to the {@code singleTask} launch mode, this activity can be
+ in a task. In contrast to the {@code singleTask} launch mode, this activity can be
started in multiple instances in different tasks if the
{@code FLAG_ACTIVITY_MULTIPLE_TASK} or {@code FLAG_ACTIVITY_NEW_DOCUMENT} is set.-->
<enum name="singleInstancePerTask" value="4" />
@@ -1328,7 +1330,7 @@
<p>Such a document is any kind of item for which an application may want to
maintain multiple simultaneous instances. Examples might be text files, web
pages, spreadsheets, or emails. Each such document will be in a separate
- task in the recent taskss list.
+ task in the recent tasks list.
<p>This attribute is equivalent to adding the flag {@link
android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch
@@ -1771,7 +1773,7 @@
</attr>
<!-- Enable hardware memory tagging (ARM MTE) in this process.
- When enabled, heap memory bugs like use-after-free and buffer overlow
+ When enabled, heap memory bugs like use-after-free and buffer overflow
are detected and result in an immediate ("sync" mode) or delayed ("async"
mode) crash instead of a silent memory corruption. Sync mode, while slower,
provides enhanced bug reports including stack traces at the time of allocation
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cbc6c2a..75f1251 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -45,9 +45,7 @@
<item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_connected_display</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_camera</xliff:g></item>
@@ -56,6 +54,8 @@
<item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
@@ -3013,14 +3013,15 @@
on the headphone/microphone jack. When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
- <!-- Whether safe headphone volume is enabled or not (country specific). -->
+ <!-- Whether safe headphone hearing is enforced by any regulation (e.g.
+ EN50332-3, EN50332-2) or not (country specific). -->
<bool name="config_safe_media_volume_enabled">true</bool>
- <!-- Whether safe headphone sound dosage warning is enabled or not
- (country specific). This value should only be overlaid to true
- when a vendor supports offload and has the HAL sound dose
- interfaces implemented. Otherwise, this can lead to a compliance
- issue with the safe hearing standards EN50332-3 and IEC62368-1.
+ <!-- Whether safe headphone sound dosage warning is enabled or not.
+ This value should only be overlaid to true when a vendor supports
+ offload and has the HAL sound dose interfaces implemented.
+ Otherwise, this can lead to a compliance issue with the safe
+ hearing standards EN50332-3 and IEC62368-1.
-->
<bool name="config_safe_sound_dosage_enabled">false</bool>
@@ -6084,6 +6085,9 @@
<!-- Default value for Settings.ASSIST_TOUCH_GESTURE_ENABLED -->
<bool name="config_assistTouchGestureEnabledDefault">true</bool>
+ <!-- Default value for Settings.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED -->
+ <bool name="config_searchPressHoldNavHandleEnabledDefault">true</bool>
+
<!-- The maximum byte size of the information contained in the bundle of
HotwordDetectedResult. -->
<integer translatable="false" name="config_hotwordDetectedResultMaxBundleSize">0</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 33c18c2..9c018c30 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1889,22 +1889,22 @@
<!-- Content description which should be used for the fingerprint icon. -->
<string name="fingerprint_icon_content_description">Fingerprint icon</string>
+ <!-- Notification name shown when the system requires the user to set up device unlock. [CHAR LIMIT=NONE] -->
+ <string name="device_unlock_notification_name">Device unlock</string>
+ <!-- Notification title shown when the system suggests the user to set up another way to unlock. [CHAR LIMIT=NONE] -->
+ <string name="alternative_unlock_setup_notification_title">Try another way to unlock</string>
+ <!-- Notification content shown when the system suggests the user to enroll their face. [CHAR LIMIT=NONE] -->
+ <string name="alternative_face_setup_notification_content">Use Face Unlock when your fingerprint isn\'t recognized, like when your fingers are wet</string>
+ <!-- Notification content shown when the system suggests the user to enroll their fingerprint. [CHAR LIMIT=NONE] -->
+ <string name="alternative_fp_setup_notification_content">Use Fingerprint Unlock when your face isn\'t recognized, like when there\'s not enough light</string>
<!-- Notification name shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_name">Face Unlock</string>
<!-- Notification title shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_title">Issue with Face Unlock</string>
<!-- Notification content shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_content">Tap to delete your face model, then add your face again</string>
- <!-- Title of a notification that directs the user to set up Face Unlock by enrolling their face. [CHAR LIMIT=NONE] -->
- <string name="face_setup_notification_title">Set up Face Unlock</string>
- <!-- Contents of a notification that directs the user to set up face unlock by enrolling their face. [CHAR LIMIT=NONE] -->
- <string name="face_setup_notification_content">Unlock your phone by looking at it</string>
<!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=NONE] -->
<string name="face_sensor_privacy_enabled">To use Face Unlock, turn on <b>Camera access</b> in Settings > Privacy</string>
- <!-- Title of a notification that directs the user to enroll a fingerprint. [CHAR LIMIT=NONE] -->
- <string name="fingerprint_setup_notification_title">Set up more ways to unlock</string>
- <!-- Contents of a notification that directs the user to enroll a fingerprint. [CHAR LIMIT=NONE] -->
- <string name="fingerprint_setup_notification_content">Tap to add a fingerprint</string>
<!-- Notification name shown when the system requires the user to re-calibrate their fingerprint. [CHAR LIMIT=NONE] -->
<string name="fingerprint_recalibrate_notification_name">Fingerprint Unlock</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8de1304..72b76c2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2584,6 +2584,12 @@
<!-- Biometric FRR config -->
<java-symbol type="fraction" name="config_biometricNotificationFrrThreshold" />
+ <!-- Biometric FRR notification messages -->
+ <java-symbol type="string" name="device_unlock_notification_name" />
+ <java-symbol type="string" name="alternative_unlock_setup_notification_title" />
+ <java-symbol type="string" name="alternative_face_setup_notification_content" />
+ <java-symbol type="string" name="alternative_fp_setup_notification_content" />
+
<!-- Device credential strings for BiometricManager -->
<java-symbol type="string" name="screen_lock_app_setting_name" />
<java-symbol type="string" name="screen_lock_dialog_default_subtitle" />
@@ -4858,6 +4864,8 @@
<java-symbol type="bool" name="config_assistLongPressHomeEnabledDefault" />
<java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
+ <java-symbol type="bool" name="config_searchPressHoldNavHandleEnabledDefault" />
+
<java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
<java-symbol type="dimen" name="config_wallpaperDimAmount" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 31755ef..a358c4f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1749,6 +1749,15 @@
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
</activity>
+
+ <activity android:name="android.view.ViewGroupTestActivity"
+ android:label="ViewGroup Test"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/layout/viewgroup_test.xml b/core/tests/coretests/res/layout/viewgroup_test.xml
new file mode 100644
index 0000000..04f4f52
--- /dev/null
+++ b/core/tests/coretests/res/layout/viewgroup_test.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Demonstrates adding/removing views from ViewGroup. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linear_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <EditText
+ android:id="@+id/view"
+ android:layout_width="20dp"
+ android:layout_height="10dp"
+ android:text="Hello World!"
+ android:background="#2F00FF00" />
+ <EditText
+ android:id="@+id/view_scale"
+ android:layout_width="20dp"
+ android:layout_height="10dp"
+ android:scaleX="0.5"
+ android:scaleY="2"
+ android:transformPivotX="0dp"
+ android:transformPivotY="0dp"
+ android:text="Hello World!"
+ android:background="#2F00FF00" />
+ <EditText
+ android:id="@+id/view_translate"
+ android:layout_width="20dp"
+ android:layout_height="10dp"
+ android:translationX="10dp"
+ android:translationY="20dp"
+ android:text="Hello World!"
+ android:background="#2F00FF00" />
+ <FrameLayout
+ android:layout_width="20dp"
+ android:layout_height="10dp">
+ <EditText
+ android:id="@+id/view_overlap_bottom"
+ android:layout_width="20dp"
+ android:layout_height="10dp"
+ android:text="Hello World!"/>
+ <Button
+ android:id="@+id/view_overlap_top"
+ android:layout_width="10dp"
+ android:layout_height="10dp"/>
+ </FrameLayout>
+
+ <FrameLayout
+ android:layout_width="20dp"
+ android:layout_height="10dp">
+ <EditText
+ android:id="@+id/view_cover_bottom"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:text="Hello World!"/>
+ <Button
+ android:id="@+id/view_cover_top"
+ android:layout_width="10dp"
+ android:layout_height="10dp"/>
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
index a84ac55..55ded9c 100644
--- a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
+++ b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
@@ -136,7 +136,11 @@
NotificationListenerService.RankingMap retrievedRankings =
retrievedRankingUpdate.getRankingMap();
assertNotNull(retrievedRankings);
- assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+ // The rankingUpdate file descriptor is only non-null in the new path.
+ if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
+ SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
+ assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+ }
NotificationListenerService.Ranking retrievedRanking =
new NotificationListenerService.Ranking();
assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
diff --git a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java
new file mode 100644
index 0000000..60a0a2a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.view;
+
+import static com.google.common.truth.Truth.assertThat;
+
+
+import android.graphics.Matrix;
+import android.graphics.Region;
+import android.platform.test.annotations.Presubmit;
+import android.widget.LinearLayout;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test basic functions of ViewGroup.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:ViewGroupTest
+ */
+@Presubmit
+@SmallTest
+public class ViewGroupGetChildLocalHitRegionTest {
+ @Rule
+ public ActivityScenarioRule<ViewGroupTestActivity> mScenarioRule =
+ new ActivityScenarioRule<>(ViewGroupTestActivity.class);
+
+ private LinearLayout mRoot;
+ private final int[] mRootLocation = new int[2];
+
+ @Before
+ public void setup() {
+ mScenarioRule.getScenario().onActivity(activity -> {
+ mRoot = activity.findViewById(R.id.linear_layout);
+ mRoot.getLocationInWindow(mRootLocation);
+ });
+ }
+
+ @Test
+ public void testGetChildLocalHitRegion() {
+ assertGetChildLocalHitRegion(R.id.view);
+ }
+
+ @Test
+ public void testGetChildLocalHitRegion_withScale() {
+ assertGetChildLocalHitRegion(R.id.view_scale);
+ }
+
+ @Test
+ public void testGetChildLocalHitRegion_withTranslate() {
+ assertGetChildLocalHitRegion(R.id.view_translate);
+ }
+
+ @Test
+ public void testGetChildLocalHitRegion_overlap_noMotionEvent() {
+ assertGetChildLocalHitRegion(R.id.view_overlap_bottom);
+ }
+ @Test
+ public void testGetChildLocalHitRegion_overlap_withMotionEvent() {
+ // In this case, view_cover_bottom is partially covered by the view_cover_top.
+ // The returned region is the bounds of the bottom view subtract the bounds of the top view.
+ assertGetChildLocalHitRegion(R.id.view_overlap_top, R.id.view_overlap_bottom);
+ }
+
+ @Test
+ public void testGetChildLocalHitRegion_cover_withMotionEvent() {
+ // In this case, view_cover_bottom is completely covered by the view_cover_top.
+ // The returned region is expected to be empty.
+ assertGetChildLocalHitRegionEmpty(R.id.view_cover_top, R.id.view_cover_bottom);
+ }
+
+ private void injectMotionEvent(View view, boolean isHover) {
+ int[] location = new int[2];
+ view.getLocationInWindow(location);
+
+ float x = location[0] + view.getWidth() / 2f;
+ float y = location[1] + view.getHeight() / 2f;
+
+ int action = isHover ? MotionEvent.ACTION_HOVER_ENTER : MotionEvent.ACTION_DOWN;
+ MotionEvent motionEvent = MotionEvent.obtain(/* downtime= */ 0, /* eventTime= */ 0, action,
+ x, y, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0,
+ /* xPrecision= */ 1, /* yPrecision= */ 1, /* deviceId= */0, /* edgeFlags= */0);
+
+ View rootView = view.getRootView();
+ rootView.dispatchPointerEvent(motionEvent);
+ }
+
+ private void assertGetChildLocalHitRegion(int viewId) {
+ assertGetChildLocalHitRegion(viewId, /* isHover= */ true);
+ assertGetChildLocalHitRegion(viewId, /* isHover= */ false);
+ }
+
+ /**
+ * Assert ViewParent#getChildLocalHitRegion for a single view.
+ * @param viewId the viewId of the tested view.
+ * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+ * region of the touch events.
+ */
+ private void assertGetChildLocalHitRegion(int viewId, boolean isHover) {
+ mScenarioRule.getScenario().onActivity(activity -> {
+ View view = activity.findViewById(viewId);
+
+ Matrix actualMatrix = new Matrix();
+ Region actualRegion = new Region(0, 0, view.getWidth(), view.getHeight());
+ boolean actualNotEmpty = view.getParent()
+ .getChildLocalHitRegion(view, actualRegion, actualMatrix, isHover);
+
+ int[] windowLocation = new int[2];
+ view.getLocationInWindow(windowLocation);
+ Matrix expectMatrix = new Matrix();
+ expectMatrix.preScale(1 / view.getScaleX(), 1 / view.getScaleY());
+ expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]);
+
+ Region expectRegion = new Region(0, 0, view.getWidth(), view.getHeight());
+
+ assertThat(actualNotEmpty).isTrue();
+ assertThat(actualMatrix).isEqualTo(expectMatrix);
+ assertThat(actualRegion).isEqualTo(expectRegion);
+ });
+ }
+
+ private void assertGetChildLocalHitRegion(int viewIdTop, int viewIdBottom) {
+ assertGetChildLocalHitRegion(viewIdTop, viewIdBottom, /* isHover= */ true);
+ assertGetChildLocalHitRegion(viewIdTop, viewIdBottom, /* isHover= */ false);
+ }
+
+ /**
+ * Assert ViewParent#getChildLocalHitRegion of a view that is covered by another view. It will
+ * inject {@link MotionEvent}s to the view on top first and then get the hit region of the
+ * bottom view.
+ *
+ * @param viewIdTop the view id of the test view on top.
+ * @param viewIdBottom the view id of the test view at the bottom.
+ * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+ * region of the touch events.
+ */
+ private void assertGetChildLocalHitRegion(int viewIdTop, int viewIdBottom, boolean isHover) {
+ mScenarioRule.getScenario().onActivity(activity -> {
+ View viewTop = activity.findViewById(viewIdTop);
+ View viewBottom = activity.findViewById(viewIdBottom);
+
+ injectMotionEvent(viewTop, isHover);
+
+ Matrix actualMatrix = new Matrix();
+ Region actualRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+ boolean actualNotEmpty = viewBottom.getParent()
+ .getChildLocalHitRegion(viewBottom, actualRegion, actualMatrix, isHover);
+
+ int[] windowLocation = new int[2];
+ viewBottom.getLocationInWindow(windowLocation);
+ Matrix expectMatrix = new Matrix();
+ expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]);
+
+ Region expectRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+ expectRegion.op(0, 0, viewTop.getWidth(), viewTop.getHeight(), Region.Op.DIFFERENCE);
+
+ assertThat(actualNotEmpty).isTrue();
+ assertThat(actualMatrix).isEqualTo(expectMatrix);
+ assertThat(actualRegion).isEqualTo(expectRegion);
+ });
+ }
+
+ private void assertGetChildLocalHitRegionEmpty(int viewIdTop, int viewIdBottom) {
+ assertGetChildLocalHitRegionEmpty(viewIdTop, viewIdBottom, /* isHover= */ true);
+ assertGetChildLocalHitRegionEmpty(viewIdTop, viewIdBottom, /* isHover= */ false);
+ }
+
+ /**
+ * Assert ViewParent#getChildLocalHitRegion returns an empty region for a view that is
+ * completely covered by another view. It will inject {@link MotionEvent}s to the view on top
+ * first and then get the hit region of the
+ * bottom view.
+ *
+ * @param viewIdTop the view id of the test view on top.
+ * @param viewIdBottom the view id of the test view at the bottom.
+ * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+ * region of the touch events.
+ */
+ private void assertGetChildLocalHitRegionEmpty(int viewIdTop, int viewIdBottom,
+ boolean isHover) {
+ mScenarioRule.getScenario().onActivity(activity -> {
+ View viewTop = activity.findViewById(viewIdTop);
+ View viewBottom = activity.findViewById(viewIdBottom);
+
+ injectMotionEvent(viewTop, isHover);
+
+ Region actualRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+ boolean actualNotEmpty = viewBottom.getParent()
+ .getChildLocalHitRegion(viewBottom, actualRegion, new Matrix(), isHover);
+
+ assertThat(actualNotEmpty).isFalse();
+ assertThat(actualRegion.isEmpty()).isTrue();
+ });
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewGroupTestActivity.java b/core/tests/coretests/src/android/view/ViewGroupTestActivity.java
new file mode 100644
index 0000000..b94bda5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+public class ViewGroupTestActivity extends Activity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.viewgroup_test);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
index 388a996..b4c72ca 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -21,7 +21,9 @@
import android.app.Instrumentation;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.Region;
import android.view.View;
import android.view.ViewGroup;
@@ -45,7 +47,7 @@
float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
final Context context = instrumentation.getTargetContext();
- // mock a parent so that HandwritingInitiator can get
+ // mock a parent so that HandwritingInitiator can get visible rect and hit region.
final ViewGroup parent = new ViewGroup(context) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
@@ -56,6 +58,14 @@
r.set(handwritingArea);
return true;
}
+
+ @Override
+ public boolean getChildLocalHitRegion(View child, Region region, Matrix matrix,
+ boolean isHover) {
+ matrix.reset();
+ region.set(handwritingArea);
+ return true;
+ }
};
View view = spy(new View(context));
diff --git a/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button.xml b/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button.xml
new file mode 100644
index 0000000..6e4752c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <path
+ android:fillColor="@color/compat_controls_background"
+ android:strokeAlpha="0.8"
+ android:fillAlpha="0.8"
+ android:pathData="M0,24 a24,24 0 1,0 48,0 a24,24 0 1,0 -48,0"/>
+ <group
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:fillColor="@color/compat_controls_text"
+ android:pathData="M19,12h-2v3h-3v2h5v-5zM7,9h3L10,7L5,7v5h2L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button_ripple.xml b/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button_ripple.xml
new file mode 100644
index 0000000..141a1ce
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/user_aspect_ratio_settings_button_ripple.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/compat_background_ripple">
+ <item android:drawable="@drawable/user_aspect_ratio_settings_button"/>
+</ripple>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
new file mode 100644
index 0000000..a0a06f1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<com.android.wm.shell.common.bubbles.BubblePopupView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginHorizontal="@dimen/bubble_popup_margin_horizontal"
+ android:layout_marginTop="@dimen/bubble_popup_margin_top"
+ android:elevation="@dimen/bubble_manage_menu_elevation"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:tint="?android:attr/colorAccent"
+ android:contentDescription="@null"
+ android:src="@drawable/pip_ic_settings"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:maxWidth="@dimen/bubble_popup_content_max_width"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/bubble_bar_education_manage_title"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:maxWidth="@dimen/bubble_popup_content_max_width"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAlignment="center"
+ android:text="@string/bubble_bar_education_manage_text"/>
+
+</com.android.wm.shell.common.bubbles.BubblePopupView>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
index dfaeeeb..257fe15 100644
--- a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
@@ -55,7 +55,7 @@
<include android:id="@+id/size_compat_hint"
android:visibility="gone"
- android:layout_width="@dimen/size_compat_hint_width"
+ android:layout_width="@dimen/compat_hint_width"
android:layout_height="wrap_content"
layout="@layout/compat_mode_hint"/>
diff --git a/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml b/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml
new file mode 100644
index 0000000..433d854
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.wm.shell.compatui.UserAspectRatioSettingsLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="bottom|end">
+
+ <include android:id="@+id/user_aspect_ratio_settings_hint"
+ android:visibility="gone"
+ android:layout_width="@dimen/compat_hint_width"
+ android:layout_height="wrap_content"
+ layout="@layout/compat_mode_hint"/>
+
+ <ImageButton
+ android:id="@+id/user_aspect_ratio_settings_button"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/compat_button_margin"
+ android:layout_marginBottom="@dimen/compat_button_margin"
+ android:src="@drawable/user_aspect_ratio_settings_button_ripple"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/user_aspect_ratio_settings_button_description"/>
+
+</com.android.wm.shell.compatui.UserAspectRatioSettingsLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 64fed1c..63a9723 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,6 +226,20 @@
<dimen name="bubble_user_education_padding_end">58dp</dimen>
<!-- Padding between the bubble and the user education text. -->
<dimen name="bubble_user_education_stack_padding">16dp</dimen>
+ <!-- Max width for the bubble popup view. -->
+ <dimen name="bubble_popup_content_max_width">300dp</dimen>
+ <!-- Horizontal margin for the bubble popup view. -->
+ <dimen name="bubble_popup_margin_horizontal">32dp</dimen>
+ <!-- Top margin for the bubble popup view. -->
+ <dimen name="bubble_popup_margin_top">16dp</dimen>
+ <!-- Width for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_width">12dp</dimen>
+ <!-- Height for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_height">10dp</dimen>
+ <!-- Corner radius for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_corner_radius">2dp</dimen>
+ <!-- Padding for the bubble popup view contents. -->
+ <dimen name="bubble_popup_padding">24dp</dimen>
<!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
<dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
<!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
@@ -260,8 +274,8 @@
+ compat_button_margin - compat_hint_corner_radius - compat_hint_point_width / 2). -->
<dimen name="compat_hint_padding_end">7dp</dimen>
- <!-- The width of the size compat hint. -->
- <dimen name="size_compat_hint_width">188dp</dimen>
+ <!-- The width of the compat hint. -->
+ <dimen name="compat_hint_width">188dp</dimen>
<!-- The width of the camera compat hint. -->
<dimen name="camera_compat_hint_width">143dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index b192fdf..00c63d7 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -163,6 +163,11 @@
<!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
<string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
+ <!-- Title text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
+ <string name="bubble_bar_education_manage_title">Control bubbles anytime</string>
+ <!-- Descriptive text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
+ <string name="bubble_bar_education_manage_text">Tap here to manage which apps and conversations can bubble</string>
+
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_bubble_title">Bubble</string>
@@ -173,7 +178,13 @@
<string name="accessibility_bubble_dismissed">Bubble dismissed.</string>
<!-- Description of the restart button in the hint of size compatibility mode. [CHAR LIMIT=NONE] -->
- <string name="restart_button_description">Tap to restart this app for a better view.</string>
+ <string name="restart_button_description">Tap to restart this app for a better view</string>
+
+ <!-- Tooltip text of the button for the user aspect ratio settings. [CHAR LIMIT=NONE] -->
+ <string name="user_aspect_ratio_settings_button_hint">Change this app\'s aspect ratio in Settings</string>
+
+ <!-- Content description of the button for the user aspect ratio settings. [CHAR LIMIT=NONE] -->
+ <string name="user_aspect_ratio_settings_button_description">Change aspect ratio</string>
<!-- Description of the camera compat button for applying stretched issues treatment in the hint for
compatibility control. [CHAR LIMIT=NONE] -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 7e09c98..ff67110 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -60,7 +60,6 @@
/**
* Encapsulates the data and UI elements of a bubble.
*/
-@VisibleForTesting
public class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
new file mode 100644
index 0000000..e57f02c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.wm.shell.bubbles
+
+import android.content.Context
+import android.util.Log
+import androidx.core.content.edit
+import com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
+
+/** Manages bubble education flags. Provides convenience methods to check the education state */
+class BubbleEducationController(private val context: Context) {
+ private val prefs = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+
+ /** Whether the user has seen the stack education */
+ @get:JvmName(name = "hasSeenStackEducation")
+ var hasSeenStackEducation: Boolean
+ get() = prefs.getBoolean(PREF_STACK_EDUCATION, false)
+ set(value) = prefs.edit { putBoolean(PREF_STACK_EDUCATION, value) }
+
+ /** Whether the user has seen the expanded view "manage" menu education */
+ @get:JvmName(name = "hasSeenManageEducation")
+ var hasSeenManageEducation: Boolean
+ get() = prefs.getBoolean(PREF_MANAGED_EDUCATION, false)
+ set(value) = prefs.edit { putBoolean(PREF_MANAGED_EDUCATION, value) }
+
+ /** Whether education view should show for the collapsed stack. */
+ fun shouldShowStackEducation(bubble: BubbleViewProvider?): Boolean {
+ val shouldShow = bubble != null &&
+ bubble.isConversationBubble && // show education for conversation bubbles only
+ (!hasSeenStackEducation || BubbleDebugConfig.forceShowUserEducation(context))
+ logDebug("Show stack edu: $shouldShow")
+ return shouldShow
+ }
+
+ /** Whether the educational view should show for the expanded view "manage" menu. */
+ fun shouldShowManageEducation(bubble: BubbleViewProvider?): Boolean {
+ val shouldShow = bubble != null &&
+ bubble.isConversationBubble && // show education for conversation bubbles only
+ (!hasSeenManageEducation || BubbleDebugConfig.forceShowUserEducation(context))
+ logDebug("Show manage edu: $shouldShow")
+ return shouldShow
+ }
+
+ private fun logDebug(message: String) {
+ if (DEBUG_USER_EDUCATION) {
+ Log.d(TAG, message)
+ }
+ }
+
+ companion object {
+ private val TAG = if (TAG_WITH_CLASS_NAME) "BubbleEducationController" else TAG_BUBBLES
+ const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
+ const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
+ }
+}
+
+/** Convenience extension method to check if the bubble is a conversation bubble */
+private val BubbleViewProvider.isConversationBubble: Boolean
+ get() = if (this is Bubble) isConversation else false
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
new file mode 100644
index 0000000..bdb09e1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.wm.shell.bubbles
+
+import android.graphics.Color
+import com.android.wm.shell.R
+import com.android.wm.shell.common.bubbles.BubblePopupDrawable
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/**
+ * A convenience method to setup the [BubblePopupView] with the correct config using local resources
+ */
+fun BubblePopupView.setup() {
+ val attrs =
+ context.obtainStyledAttributes(
+ intArrayOf(
+ com.android.internal.R.attr.materialColorSurface,
+ android.R.attr.dialogCornerRadius
+ )
+ )
+
+ val res = context.resources
+ val config =
+ BubblePopupDrawable.Config(
+ color = attrs.getColor(0, Color.WHITE),
+ cornerRadius = attrs.getDimension(1, 0f),
+ contentPadding = res.getDimensionPixelSize(R.dimen.bubble_popup_padding),
+ arrowWidth = res.getDimension(R.dimen.bubble_popup_arrow_width),
+ arrowHeight = res.getDimension(R.dimen.bubble_popup_arrow_height),
+ arrowRadius = res.getDimension(R.dimen.bubble_popup_arrow_corner_radius)
+ )
+ attrs.recycle()
+ setupBackground(config)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index da5974f..74f830e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -46,7 +46,6 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -108,12 +107,6 @@
*/
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
-
- // LINT.IfChange
- public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
- SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
- // LINT.ThenChange(com/android/launcher3/taskbar/bubbles/BubbleDismissController.java)
-
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 33629f9..c20733a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -19,7 +19,6 @@
import static android.view.View.LAYOUT_DIRECTION_RTL;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
import android.content.res.Resources;
import android.graphics.Path;
@@ -355,7 +354,6 @@
mMagnetizedBubbleDraggingOut.setMagnetListener(listener);
mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
- mMagnetizedBubbleDraggingOut.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
}
private void springBubbleTo(View bubble, float x, float y) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 5533842..4bb1ab4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.bubbles.animation;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
import android.content.ContentResolver;
import android.content.res.Resources;
@@ -1026,7 +1025,6 @@
};
mMagnetizedStack.setHapticsEnabled(true);
mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
- mMagnetizedStack.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
}
final ContentResolver contentResolver = mLayout.getContext().getContentResolver();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 6b6d6ba..79f188a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -39,7 +39,6 @@
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.taskview.TaskView;
-import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -48,6 +47,18 @@
* {@link BubbleController#isShowingAsBubbleBar()}
*/
public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener {
+ /**
+ * The expanded view listener notifying the {@link BubbleBarLayerView} about the internal
+ * actions and events
+ */
+ public interface Listener {
+ /** Called when the task view task is first created. */
+ void onTaskCreated();
+ /** Called when expanded view needs to un-bubble the given conversation */
+ void onUnBubbleConversation(String bubbleKey);
+ /** Called when expanded view task view back button pressed */
+ void onBackPressed();
+ }
private static final String TAG = BubbleBarExpandedView.class.getSimpleName();
private static final int INVALID_TASK_ID = -1;
@@ -57,7 +68,7 @@
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
private @Nullable Supplier<Rect> mLayerBoundsSupplier;
- private @Nullable Consumer<String> mUnBubbleConversationCallback;
+ private @Nullable Listener mListener;
private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
private @Nullable TaskView mTaskView;
@@ -145,15 +156,13 @@
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@Override
public void onMenuVisibilityChanged(boolean visible) {
- if (mTaskView == null || mLayerBoundsSupplier == null) return;
- // Updates the obscured touchable region for the task surface.
- mTaskView.setObscuredTouchRect(visible ? mLayerBoundsSupplier.get() : null);
+ setObscured(visible);
}
@Override
public void onUnBubbleConversation(Bubble bubble) {
- if (mUnBubbleConversationCallback != null) {
- mUnBubbleConversationCallback.accept(bubble.getKey());
+ if (mListener != null) {
+ mListener.onUnBubbleConversation(bubble.getKey());
}
}
@@ -231,6 +240,9 @@
public void onTaskCreated() {
setContentVisibility(true);
updateHandleColor(false /* animated */);
+ if (mListener != null) {
+ mListener.onTaskCreated();
+ }
}
@Override
@@ -240,7 +252,8 @@
@Override
public void onBackPressed() {
- mController.collapseStack();
+ if (mListener == null) return;
+ mListener.onBackPressed();
}
/** Cleans up task view, should be called when the bubble is no longer active. */
@@ -254,6 +267,18 @@
mMenuViewController.hideMenu(false /* animated */);
}
+ /**
+ * Hides the current modal menu view or collapses the bubble stack.
+ * Called from {@link BubbleBarLayerView}
+ */
+ public void hideMenuOrCollapse() {
+ if (mMenuViewController.isMenuVisible()) {
+ mMenuViewController.hideMenu(/* animated = */ true);
+ } else {
+ mController.collapseStack();
+ }
+ }
+
/** Updates the bubble shown in the expanded view. */
public void update(Bubble bubble) {
mBubbleTaskViewHelper.update(bubble);
@@ -270,10 +295,16 @@
mLayerBoundsSupplier = supplier;
}
- /** Sets the function to call to un-bubble the given conversation. */
- public void setUnBubbleConversationCallback(
- @Nullable Consumer<String> unBubbleConversationCallback) {
- mUnBubbleConversationCallback = unBubbleConversationCallback;
+ /** Sets expanded view listener */
+ void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ /** Sets whether the view is obscured by some modal view */
+ void setObscured(boolean obscured) {
+ if (mTaskView == null || mLayerBoundsSupplier == null) return;
+ // Updates the obscured touchable region for the task surface.
+ mTaskView.setObscuredTouchRect(obscured ? mLayerBoundsSupplier.get() : null);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bc04bfc..8f11253 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -52,6 +52,7 @@
private final BubbleController mBubbleController;
private final BubblePositioner mPositioner;
private final BubbleBarAnimationHelper mAnimationHelper;
+ private final BubbleEducationViewController mEducationViewController;
private final View mScrimView;
@Nullable
@@ -80,6 +81,10 @@
mAnimationHelper = new BubbleBarAnimationHelper(context,
this, mPositioner);
+ mEducationViewController = new BubbleEducationViewController(context, (boolean visible) -> {
+ if (mExpandedView == null) return;
+ mExpandedView.setObscured(visible);
+ });
mScrimView = new View(getContext());
mScrimView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -90,9 +95,7 @@
mScrimView.setBackgroundDrawable(new ColorDrawable(
getResources().getColor(android.R.color.system_neutral1_1000)));
- setOnClickListener(view -> {
- mBubbleController.collapseStack();
- });
+ setOnClickListener(view -> hideMenuOrCollapse());
}
@Override
@@ -108,6 +111,7 @@
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
if (mExpandedView != null) {
+ mEducationViewController.hideManageEducation(/* animated = */ false);
removeView(mExpandedView);
mExpandedView = null;
}
@@ -162,14 +166,27 @@
final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
mExpandedView.setVisibility(GONE);
- mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
- mExpandedView.setUnBubbleConversationCallback(bubbleKey -> {
- if (mUnBubbleConversationCallback != null) {
- mUnBubbleConversationCallback.accept(bubbleKey);
+ mExpandedView.setListener(new BubbleBarExpandedView.Listener() {
+ @Override
+ public void onTaskCreated() {
+ mEducationViewController.maybeShowManageEducation(b, mExpandedView);
+ }
+
+ @Override
+ public void onUnBubbleConversation(String bubbleKey) {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubbleKey);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ hideMenuOrCollapse();
}
});
- mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
+
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
@@ -193,6 +210,7 @@
public void collapse() {
mIsExpanded = false;
final BubbleBarExpandedView viewToRemove = mExpandedView;
+ mEducationViewController.hideManageEducation(/* animated = */ true);
mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
@@ -206,6 +224,17 @@
mUnBubbleConversationCallback = unBubbleConversationCallback;
}
+ /** Hides the current modal education/menu view, expanded view or collapses the bubble stack */
+ private void hideMenuOrCollapse() {
+ if (mEducationViewController.isManageEducationVisible()) {
+ mEducationViewController.hideManageEducation(/* animated = */ true);
+ } else if (isExpanded() && mExpandedView != null) {
+ mExpandedView.hideMenuOrCollapse();
+ } else {
+ mBubbleController.collapseStack();
+ }
+ }
+
/** Updates the expanded view size and position. */
private void updateExpandedView() {
if (mExpandedView == null) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
index 8be140c..81e7582 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -56,6 +56,11 @@
SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
}
+ /** Tells if the menu is visible or being animated */
+ boolean isMenuVisible() {
+ return mMenuView != null && mMenuView.getVisibility() == View.VISIBLE;
+ }
+
/** Sets menu actions listener */
void setListener(@Nullable Listener listener) {
mListener = listener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
new file mode 100644
index 0000000..7b39c6f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.wm.shell.bubbles.bar
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.view.doOnLayout
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.BubbleViewProvider
+import com.android.wm.shell.bubbles.setup
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/** Manages bubble education presentation and animation */
+class BubbleEducationViewController(private val context: Context, private val listener: Listener) {
+ interface Listener {
+ fun onManageEducationVisibilityChanged(isVisible: Boolean)
+ }
+
+ private var rootView: ViewGroup? = null
+ private var educationView: BubblePopupView? = null
+ private var animator: PhysicsAnimator<BubblePopupView>? = null
+
+ private val springConfig by lazy {
+ PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM,
+ SpringForce.DAMPING_RATIO_LOW_BOUNCY
+ )
+ }
+
+ private val controller by lazy { BubbleEducationController(context) }
+
+ /** Whether the education view is visible or being animated */
+ val isManageEducationVisible: Boolean
+ get() = educationView != null && rootView != null
+
+ /**
+ * Show manage bubble education if hasn't been shown before
+ *
+ * @param bubble the bubble used for the manage education check
+ * @param root the view to show manage education in
+ */
+ fun maybeShowManageEducation(bubble: BubbleViewProvider, root: ViewGroup) {
+ if (!controller.shouldShowManageEducation(bubble)) return
+ showManageEducation(root)
+ }
+
+ /**
+ * Hide the manage education view if visible
+ *
+ * @param animated whether should hide with animation
+ */
+ fun hideManageEducation(animated: Boolean) {
+ rootView?.let {
+ fun cleanUp() {
+ it.removeView(educationView)
+ rootView = null
+ listener.onManageEducationVisibilityChanged(isVisible = false)
+ }
+
+ if (animated) {
+ animateTransition(show = false, ::cleanUp)
+ } else {
+ cleanUp()
+ }
+ }
+ }
+
+ /**
+ * Show manage education with animation
+ *
+ * @param root the view to show manage education in
+ */
+ private fun showManageEducation(root: ViewGroup) {
+ hideManageEducation(animated = false)
+ if (educationView == null) {
+ val eduView = createEducationView(root)
+ educationView = eduView
+ animator = createAnimation(eduView)
+ }
+ root.addView(educationView)
+ rootView = root
+ animateTransition(show = true) {
+ controller.hasSeenManageEducation = true
+ listener.onManageEducationVisibilityChanged(isVisible = true)
+ }
+ }
+
+ /**
+ * Animate show/hide transition for the education view
+ *
+ * @param show whether to show or hide the view
+ * @param endActions a closure to be called when the animation completes
+ */
+ private fun animateTransition(show: Boolean, endActions: () -> Unit) {
+ animator?.let { animator ->
+ animator
+ .spring(DynamicAnimation.ALPHA, if (show) 1f else 0f)
+ .spring(DynamicAnimation.SCALE_X, if (show) 1f else EDU_SCALE_HIDDEN)
+ .spring(DynamicAnimation.SCALE_Y, if (show) 1f else EDU_SCALE_HIDDEN)
+ .withEndActions(endActions)
+ .start()
+ } ?: endActions()
+ }
+
+ private fun createEducationView(root: ViewGroup): BubblePopupView {
+ val view =
+ LayoutInflater.from(context).inflate(R.layout.bubble_bar_manage_education, root, false)
+ as BubblePopupView
+
+ return view.apply {
+ setup()
+ alpha = 0f
+ pivotY = 0f
+ scaleX = EDU_SCALE_HIDDEN
+ scaleY = EDU_SCALE_HIDDEN
+ doOnLayout { it.pivotX = it.width / 2f }
+ setOnClickListener { hideManageEducation(animated = true) }
+ }
+ }
+
+ private fun createAnimation(view: BubblePopupView): PhysicsAnimator<BubblePopupView> {
+ val animator = PhysicsAnimator.getInstance(view)
+ animator.setDefaultSpringConfig(springConfig)
+ return animator
+ }
+
+ companion object {
+ private const val EDU_SCALE_HIDDEN = 0.5f
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
new file mode 100644
index 0000000..8b5283d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
@@ -0,0 +1,232 @@
+/*
+ * 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.wm.shell.common.bubbles
+
+import android.annotation.ColorInt
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import kotlin.math.atan
+import kotlin.math.cos
+import kotlin.math.sin
+import kotlin.properties.Delegates
+
+/** A drawable for the [BubblePopupView] that draws a popup background with a directional arrow */
+class BubblePopupDrawable(private val config: Config) : Drawable() {
+ /** The direction of the arrow in the popup drawable */
+ enum class ArrowDirection {
+ UP,
+ DOWN
+ }
+
+ /** The arrow position on the side of the popup bubble */
+ sealed class ArrowPosition {
+ object Start : ArrowPosition()
+ object Center : ArrowPosition()
+ object End : ArrowPosition()
+ class Custom(val value: Float) : ArrowPosition()
+ }
+
+ /** The configuration for drawable features */
+ data class Config(
+ @ColorInt val color: Int,
+ val cornerRadius: Float,
+ val contentPadding: Int,
+ val arrowWidth: Float,
+ val arrowHeight: Float,
+ val arrowRadius: Float
+ )
+
+ /**
+ * The direction of the arrow in the popup drawable. It affects the content padding and requires
+ * it to be updated in the view.
+ */
+ var arrowDirection: ArrowDirection by
+ Delegates.observable(ArrowDirection.UP) { _, _, _ -> requestPathUpdate() }
+
+ /**
+ * Arrow position along the X axis and its direction. The position is adjusted to the content
+ * corner radius when applied so it doesn't go into rounded corner area
+ */
+ var arrowPosition: ArrowPosition by
+ Delegates.observable(ArrowPosition.Center) { _, _, _ -> requestPathUpdate() }
+
+ private val path = Path()
+ private val paint = Paint()
+ private var shouldUpdatePath = true
+
+ init {
+ paint.color = config.color
+ paint.style = Paint.Style.FILL
+ paint.isAntiAlias = true
+ }
+
+ override fun draw(canvas: Canvas) {
+ updatePathIfNeeded()
+ canvas.drawPath(path, paint)
+ }
+
+ override fun onBoundsChange(bounds: Rect?) {
+ requestPathUpdate()
+ }
+
+ /** Should be applied to the view padding if arrow direction changes */
+ override fun getPadding(padding: Rect): Boolean {
+ padding.set(
+ config.contentPadding,
+ config.contentPadding,
+ config.contentPadding,
+ config.contentPadding
+ )
+ when (arrowDirection) {
+ ArrowDirection.UP -> padding.top += config.arrowHeight.toInt()
+ ArrowDirection.DOWN -> padding.bottom += config.arrowHeight.toInt()
+ }
+ return true
+ }
+
+ override fun getOutline(outline: Outline) {
+ updatePathIfNeeded()
+ outline.setPath(path)
+ }
+
+ override fun getOpacity(): Int {
+ return paint.alpha
+ }
+
+ override fun setAlpha(alpha: Int) {
+ paint.alpha = alpha
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ paint.colorFilter = colorFilter
+ }
+
+ /** Schedules path update for the next redraw */
+ private fun requestPathUpdate() {
+ shouldUpdatePath = true
+ }
+
+ /** Updates the path if required, when bounds or arrow direction/position changes */
+ private fun updatePathIfNeeded() {
+ if (shouldUpdatePath) {
+ updatePath()
+ shouldUpdatePath = false
+ }
+ }
+
+ /** Updates the path value using the current bounds, config, arrow direction and position */
+ private fun updatePath() {
+ if (bounds.isEmpty) return
+ // Reset the path state
+ path.reset()
+ // The content rect where the filled rounded rect will be drawn
+ val contentRect = RectF(bounds)
+ when (arrowDirection) {
+ ArrowDirection.UP -> {
+ // Add rounded arrow pointing up to the path
+ addRoundedArrowPositioned(path, arrowPosition)
+ // Inset content rect by the arrow size from the top
+ contentRect.top += config.arrowHeight
+ }
+ ArrowDirection.DOWN -> {
+ val matrix = Matrix()
+ // Flip the path with the matrix to draw arrow pointing down
+ matrix.setScale(1f, -1f, bounds.width() / 2f, bounds.height() / 2f)
+ path.transform(matrix)
+ // Add rounded arrow with the flipped matrix applied, will point down
+ addRoundedArrowPositioned(path, arrowPosition)
+ // Restore the path matrix to the original state with inverted matrix
+ matrix.invert(matrix)
+ path.transform(matrix)
+ // Inset content rect by the arrow size from the bottom
+ contentRect.bottom -= config.arrowHeight
+ }
+ }
+ // Add the content area rounded rect
+ path.addRoundRect(contentRect, config.cornerRadius, config.cornerRadius, Path.Direction.CW)
+ }
+
+ /** Add a rounded arrow pointing up in the horizontal position on the canvas */
+ private fun addRoundedArrowPositioned(path: Path, position: ArrowPosition) {
+ val matrix = Matrix()
+ var translationX = positionValue(position) - config.arrowWidth / 2
+ // Offset to position between rounded corners of the content view
+ translationX = translationX.coerceIn(config.cornerRadius,
+ bounds.width() - config.cornerRadius - config.arrowWidth)
+ // Translate to add the arrow in the center horizontally
+ matrix.setTranslate(-translationX, 0f)
+ path.transform(matrix)
+ // Add rounded arrow
+ addRoundedArrow(path)
+ // Restore the path matrix to the original state with inverted matrix
+ matrix.invert(matrix)
+ path.transform(matrix)
+ }
+
+ /** Adds a rounded arrow pointing up to the path, can be flipped if needed */
+ private fun addRoundedArrow(path: Path) {
+ // Theta is half of the angle inside the triangle tip
+ val thetaTan = config.arrowWidth / (config.arrowHeight * 2f)
+ val theta = atan(thetaTan)
+ val thetaDeg = Math.toDegrees(theta.toDouble()).toFloat()
+ // The center Y value of the circle for the triangle tip
+ val tipCircleCenterY = config.arrowRadius / sin(theta)
+ // The length from triangle tip to intersection point with the circle
+ val tipIntersectionSideLength = config.arrowRadius / thetaTan
+ // The offset from the top to the point of intersection
+ val intersectionTopOffset = tipIntersectionSideLength * cos(theta)
+ // The offset from the center to the point of intersection
+ val intersectionCenterOffset = tipIntersectionSideLength * sin(theta)
+ // The center X of the triangle
+ val arrowCenterX = config.arrowWidth / 2f
+
+ // Set initial position in bottom left of the arrow
+ path.moveTo(0f, config.arrowHeight)
+ // Add the left side of the triangle
+ path.lineTo(arrowCenterX - intersectionCenterOffset, intersectionTopOffset)
+ // Add the arc from the left to the right side of the triangle
+ path.arcTo(
+ /* left = */ arrowCenterX - config.arrowRadius,
+ /* top = */ tipCircleCenterY - config.arrowRadius,
+ /* right = */ arrowCenterX + config.arrowRadius,
+ /* bottom = */ tipCircleCenterY + config.arrowRadius,
+ /* startAngle = */ 180 + thetaDeg,
+ /* sweepAngle = */ 180 - (2 * thetaDeg),
+ /* forceMoveTo = */ false
+ )
+ // Add the right side of the triangle
+ path.lineTo(config.arrowWidth, config.arrowHeight)
+ // Close the path
+ path.close()
+ }
+
+ /** The value of the arrow position provided the position and current bounds */
+ private fun positionValue(position: ArrowPosition): Float {
+ return when (position) {
+ is ArrowPosition.Start -> 0f
+ is ArrowPosition.Center -> bounds.width().toFloat() / 2f
+ is ArrowPosition.End -> bounds.width().toFloat()
+ is ArrowPosition.Custom -> position.value
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
new file mode 100644
index 0000000..f8a4946
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.wm.shell.common.bubbles
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.widget.LinearLayout
+
+/** A popup container view that uses [BubblePopupDrawable] as a background */
+open class BubblePopupView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+ private var popupDrawable: BubblePopupDrawable? = null
+
+ /**
+ * Sets up the popup drawable with the config provided. Required to remove dependency on local
+ * resources
+ */
+ fun setupBackground(config: BubblePopupDrawable.Config) {
+ popupDrawable = BubblePopupDrawable(config)
+ background = popupDrawable
+ forceLayout()
+ }
+
+ /**
+ * Sets the arrow direction for the background drawable and updates the padding to fit the
+ * content inside of the popup drawable
+ */
+ fun setArrowDirection(direction: BubblePopupDrawable.ArrowDirection) {
+ popupDrawable?.let {
+ it.arrowDirection = direction
+ val padding = Rect()
+ if (it.getPadding(padding)) {
+ setPadding(padding.left, padding.top, padding.right, padding.bottom)
+ }
+ }
+ }
+
+ /** Sets the arrow position for the background drawable and triggers redraw */
+ fun setArrowPosition(position: BubblePopupDrawable.ArrowPosition) {
+ popupDrawable?.let {
+ it.arrowPosition = position
+ invalidate()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
new file mode 100644
index 0000000..642dacc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.wm.shell.common.pip
+
+import android.app.TaskInfo
+import android.content.pm.PackageManager
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+
+/**
+ * Helper class that ends PiP log to UiEvent, see also go/uievent
+ */
+class PipUiEventLogger(
+ private val mUiEventLogger: UiEventLogger,
+ private val mPackageManager: PackageManager
+) {
+ private var mPackageName: String? = null
+ private var mPackageUid = INVALID_PACKAGE_UID
+ fun setTaskInfo(taskInfo: TaskInfo?) {
+ if (taskInfo?.topActivity != null) {
+ // safe because topActivity is guaranteed non-null here
+ mPackageName = taskInfo.topActivity!!.packageName
+ mPackageUid = getUid(mPackageName!!, taskInfo.userId)
+ } else {
+ mPackageName = null
+ mPackageUid = INVALID_PACKAGE_UID
+ }
+ }
+
+ /**
+ * Sends log via UiEvent, reference go/uievent for how to debug locally
+ */
+ fun log(event: PipUiEventEnum?) {
+ if (mPackageName == null || mPackageUid == INVALID_PACKAGE_UID) {
+ return
+ }
+ mUiEventLogger.log(event!!, mPackageUid, mPackageName)
+ }
+
+ private fun getUid(packageName: String, userId: Int): Int {
+ var uid = INVALID_PACKAGE_UID
+ try {
+ uid = mPackageManager.getApplicationInfoAsUser(
+ packageName, 0 /* ApplicationInfoFlags */, userId
+ ).uid
+ } catch (e: PackageManager.NameNotFoundException) {
+ // do nothing.
+ }
+ return uid
+ }
+
+ /**
+ * Enums for logging the PiP events to UiEvent
+ */
+ enum class PipUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Activity enters picture-in-picture mode")
+ PICTURE_IN_PICTURE_ENTER(603),
+
+ @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
+ PICTURE_IN_PICTURE_AUTO_ENTER(1313),
+
+ @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
+ PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
+
+ @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
+ PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
+
+ @UiEvent(doc = "Removes picture-in-picture by tap close button")
+ PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
+
+ @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
+ PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
+
+ @UiEvent(doc = "Shows picture-in-picture menu")
+ PICTURE_IN_PICTURE_SHOW_MENU(607),
+
+ @UiEvent(doc = "Hides picture-in-picture menu")
+ PICTURE_IN_PICTURE_HIDE_MENU(608),
+
+ @UiEvent(
+ doc = "Changes the aspect ratio of picture-in-picture window. This is inherited" +
+ " from previous Tron-based logging and currently not in use."
+ )
+ PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
+
+ @UiEvent(doc = "User resize of the picture-in-picture window")
+ PICTURE_IN_PICTURE_RESIZE(610),
+
+ @UiEvent(doc = "User unstashed picture-in-picture")
+ PICTURE_IN_PICTURE_STASH_UNSTASHED(709),
+
+ @UiEvent(doc = "User stashed picture-in-picture to the left side")
+ PICTURE_IN_PICTURE_STASH_LEFT(710),
+
+ @UiEvent(doc = "User stashed picture-in-picture to the right side")
+ PICTURE_IN_PICTURE_STASH_RIGHT(711),
+
+ @UiEvent(doc = "User taps on the settings button in PiP menu")
+ PICTURE_IN_PICTURE_SHOW_SETTINGS(933),
+
+ @UiEvent(doc = "Closes PiP with app-provided close action")
+ PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058);
+
+ override fun getId(): Int {
+ return mId
+ }
+ }
+
+ companion object {
+ private const val INVALID_PACKAGE_UID = -1
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
index ef93a33..be1b9b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.common.split;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -60,7 +61,8 @@
public static final int[] CONTROLLED_WINDOWING_MODES =
{WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
+ {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW,
+ WINDOWING_MODE_FREEFORM};
/** Flag applied to a transition change to identify it as a divider bar for animation. */
public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 62b0799..54f8984 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -16,12 +16,17 @@
package com.android.wm.shell.compatui;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.app.TaskInfo.CameraCompatControlState;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -41,7 +46,6 @@
import com.android.wm.shell.common.DockStateReader;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -104,6 +108,13 @@
private Set<Integer> mSetOfTaskIdsShowingRestartDialog = new HashSet<>();
/**
+ * The active user aspect ratio settings button layout if there is one (there can be at most
+ * one active).
+ */
+ @Nullable
+ private UserAspectRatioSettingsWindowManager mUserAspectRatioSettingsLayout;
+
+ /**
* The active Letterbox Education layout if there is one (there can be at most one active).
*
* <p>An active layout is a layout that is eligible to be shown for the associated task but
@@ -121,38 +132,51 @@
/** Avoid creating display context frequently for non-default display. */
private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
+ @NonNull
private final Context mContext;
+ @NonNull
private final ShellController mShellController;
+ @NonNull
private final DisplayController mDisplayController;
+ @NonNull
private final DisplayInsetsController mDisplayInsetsController;
+ @NonNull
private final DisplayImeController mImeController;
+ @NonNull
private final SyncTransactionQueue mSyncQueue;
+ @NonNull
private final ShellExecutor mMainExecutor;
+ @NonNull
private final Lazy<Transitions> mTransitionsLazy;
+ @NonNull
private final DockStateReader mDockStateReader;
+ @NonNull
private final CompatUIConfiguration mCompatUIConfiguration;
// Only show each hint once automatically in the process life.
+ @NonNull
private final CompatUIHintsState mCompatUIHintsState;
+ @NonNull
private final CompatUIShellCommandHandler mCompatUIShellCommandHandler;
- private CompatUICallback mCallback;
+ @Nullable
+ private CompatUICallback mCompatUICallback;
// Indicates if the keyguard is currently showing, in which case compat UIs shouldn't
// be shown.
private boolean mKeyguardShowing;
- public CompatUIController(Context context,
- ShellInit shellInit,
- ShellController shellController,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- DisplayImeController imeController,
- SyncTransactionQueue syncQueue,
- ShellExecutor mainExecutor,
- Lazy<Transitions> transitionsLazy,
- DockStateReader dockStateReader,
- CompatUIConfiguration compatUIConfiguration,
- CompatUIShellCommandHandler compatUIShellCommandHandler) {
+ public CompatUIController(@NonNull Context context,
+ @NonNull ShellInit shellInit,
+ @NonNull ShellController shellController,
+ @NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
+ @NonNull DisplayImeController imeController,
+ @NonNull SyncTransactionQueue syncQueue,
+ @NonNull ShellExecutor mainExecutor,
+ @NonNull Lazy<Transitions> transitionsLazy,
+ @NonNull DockStateReader dockStateReader,
+ @NonNull CompatUIConfiguration compatUIConfiguration,
+ @NonNull CompatUIShellCommandHandler compatUIShellCommandHandler) {
mContext = context;
mShellController = shellController;
mDisplayController = displayController;
@@ -175,9 +199,9 @@
mCompatUIShellCommandHandler.onInit();
}
- /** Sets the callback for UI interactions. */
- public void setCompatUICallback(CompatUICallback callback) {
- mCallback = callback;
+ /** Sets the callback for Compat UI interactions. */
+ public void setCompatUICallback(@NonNull CompatUICallback compatUiCallback) {
+ mCompatUICallback = compatUiCallback;
}
/**
@@ -187,7 +211,7 @@
* @param taskInfo {@link TaskInfo} task the activity is in.
* @param taskListener listener to handle the Task Surface placement.
*/
- public void onCompatInfoChanged(TaskInfo taskInfo,
+ public void onCompatInfoChanged(@NonNull TaskInfo taskInfo,
@Nullable ShellTaskOrganizer.TaskListener taskListener) {
if (taskInfo != null && !taskInfo.topActivityInSizeCompat) {
mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
@@ -203,6 +227,16 @@
createOrUpdateRestartDialogLayout(taskInfo, taskListener);
if (mCompatUIConfiguration.getHasSeenLetterboxEducation(taskInfo.userId)) {
createOrUpdateReachabilityEduLayout(taskInfo, taskListener);
+ // The user aspect ratio button should not be handled when a new TaskInfo is
+ // sent because of a double tap or when in multi-window mode.
+ if (taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ mUserAspectRatioSettingsLayout.release();
+ mUserAspectRatioSettingsLayout = null;
+ return;
+ }
+ if (!taskInfo.isFromLetterboxDoubleTap) {
+ createOrUpdateUserAspectRatioSettingsLayout(taskInfo, taskListener);
+ }
}
}
@@ -280,8 +314,8 @@
return mDisplaysWithIme.contains(displayId);
}
- private void createOrUpdateCompatLayout(TaskInfo taskInfo,
- ShellTaskOrganizer.TaskListener taskListener) {
+ private void createOrUpdateCompatLayout(@NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
CompatUIWindowManager layout = mActiveCompatLayouts.get(taskInfo.taskId);
if (layout != null) {
if (layout.needsToBeRecreated(taskInfo, taskListener)) {
@@ -314,7 +348,7 @@
CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
return new CompatUIWindowManager(context,
- taskInfo, mSyncQueue, mCallback, taskListener,
+ taskInfo, mSyncQueue, mCompatUICallback, taskListener,
mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState,
mCompatUIConfiguration, this::onRestartButtonClicked);
}
@@ -328,12 +362,12 @@
mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId);
onCompatInfoChanged(taskInfoState.first, taskInfoState.second);
} else {
- mCallback.onSizeCompatRestartButtonClicked(taskInfoState.first.taskId);
+ mCompatUICallback.onSizeCompatRestartButtonClicked(taskInfoState.first.taskId);
}
}
- private void createOrUpdateLetterboxEduLayout(TaskInfo taskInfo,
- ShellTaskOrganizer.TaskListener taskListener) {
+ private void createOrUpdateLetterboxEduLayout(@NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
if (mActiveLetterboxEduLayout != null) {
if (mActiveLetterboxEduLayout.needsToBeRecreated(taskInfo, taskListener)) {
mActiveLetterboxEduLayout.release();
@@ -342,6 +376,7 @@
if (!mActiveLetterboxEduLayout.updateCompatInfo(taskInfo, taskListener,
showOnDisplay(mActiveLetterboxEduLayout.getDisplayId()))) {
// The layout is no longer eligible to be shown, clear active layout.
+ mActiveLetterboxEduLayout.release();
mActiveLetterboxEduLayout = null;
}
return;
@@ -371,19 +406,13 @@
ShellTaskOrganizer.TaskListener taskListener) {
return new LetterboxEduWindowManager(context, taskInfo,
mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
- mTransitionsLazy.get(), this::onLetterboxEduDismissed, mDockStateReader,
- mCompatUIConfiguration);
+ mTransitionsLazy.get(),
+ stateInfo -> createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second),
+ mDockStateReader, mCompatUIConfiguration);
}
- private void onLetterboxEduDismissed(
- Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) {
- mActiveLetterboxEduLayout = null;
- // We need to update the UI
- createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second);
- }
-
- private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo,
- ShellTaskOrganizer.TaskListener taskListener) {
+ private void createOrUpdateRestartDialogLayout(@NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
RestartDialogWindowManager layout =
mTaskIdToRestartDialogWindowManagerMap.get(taskInfo.taskId);
if (layout != null) {
@@ -428,7 +457,7 @@
private void onRestartDialogCallback(
Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) {
mTaskIdToRestartDialogWindowManagerMap.remove(stateInfo.first.taskId);
- mCallback.onSizeCompatRestartButtonClicked(stateInfo.first.taskId);
+ mCompatUICallback.onSizeCompatRestartButtonClicked(stateInfo.first.taskId);
}
private void onRestartDialogDismissCallback(
@@ -437,8 +466,8 @@
onCompatInfoChanged(stateInfo.first, stateInfo.second);
}
- private void createOrUpdateReachabilityEduLayout(TaskInfo taskInfo,
- ShellTaskOrganizer.TaskListener taskListener) {
+ private void createOrUpdateReachabilityEduLayout(@NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
if (mActiveReachabilityEduLayout != null) {
if (mActiveReachabilityEduLayout.needsToBeRecreated(taskInfo, taskListener)) {
mActiveReachabilityEduLayout.release();
@@ -448,6 +477,7 @@
if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener,
showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) {
// The layout is no longer eligible to be shown, remove from active layouts.
+ mActiveReachabilityEduLayout.release();
mActiveReachabilityEduLayout = null;
}
return;
@@ -478,14 +508,67 @@
ShellTaskOrganizer.TaskListener taskListener) {
return new ReachabilityEduWindowManager(context, taskInfo, mSyncQueue,
taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
- mCompatUIConfiguration, mMainExecutor);
+ mCompatUIConfiguration, mMainExecutor, this::onInitialReachabilityEduDismissed);
}
+ private void onInitialReachabilityEduDismissed(@NonNull TaskInfo taskInfo,
+ @NonNull ShellTaskOrganizer.TaskListener taskListener) {
+ // We need to update the UI otherwise it will not be shown until the user relaunches the app
+ createOrUpdateUserAspectRatioSettingsLayout(taskInfo, taskListener);
+ }
+
+ private void createOrUpdateUserAspectRatioSettingsLayout(@NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
+ if (mUserAspectRatioSettingsLayout != null) {
+ if (mUserAspectRatioSettingsLayout.needsToBeRecreated(taskInfo, taskListener)) {
+ mUserAspectRatioSettingsLayout.release();
+ mUserAspectRatioSettingsLayout = null;
+ } else {
+ // UI already exists, update the UI layout.
+ if (!mUserAspectRatioSettingsLayout.updateCompatInfo(taskInfo, taskListener,
+ showOnDisplay(mUserAspectRatioSettingsLayout.getDisplayId()))) {
+ mUserAspectRatioSettingsLayout.release();
+ mUserAspectRatioSettingsLayout = null;
+ }
+ return;
+ }
+ }
+
+ // Create a new UI layout.
+ final Context context = getOrCreateDisplayContext(taskInfo.displayId);
+ if (context == null) {
+ return;
+ }
+ final UserAspectRatioSettingsWindowManager newLayout =
+ createUserAspectRatioSettingsWindowManager(context, taskInfo, taskListener);
+ if (newLayout.createLayout(showOnDisplay(taskInfo.displayId))) {
+ // The new layout is eligible to be shown, add it the active layouts.
+ mUserAspectRatioSettingsLayout = newLayout;
+ }
+ }
+
+ @VisibleForTesting
+ @NonNull
+ UserAspectRatioSettingsWindowManager createUserAspectRatioSettingsWindowManager(
+ @NonNull Context context, @NonNull TaskInfo taskInfo,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener) {
+ return new UserAspectRatioSettingsWindowManager(context, taskInfo, mSyncQueue,
+ taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+ mCompatUIHintsState, this::launchUserAspectRatioSettings, mMainExecutor);
+ }
+
+ private void launchUserAspectRatioSettings(
+ @NonNull TaskInfo taskInfo, @NonNull ShellTaskOrganizer.TaskListener taskListener) {
+ final Intent intent = new Intent(Settings.ACTION_MANAGE_USER_ASPECT_RATIO_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+ }
private void removeLayouts(int taskId) {
- final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId);
- if (layout != null) {
- layout.release();
+ final CompatUIWindowManager compatLayout = mActiveCompatLayouts.get(taskId);
+ if (compatLayout != null) {
+ compatLayout.release();
mActiveCompatLayouts.remove(taskId);
}
@@ -506,6 +589,12 @@
mActiveReachabilityEduLayout.release();
mActiveReachabilityEduLayout = null;
}
+
+ if (mUserAspectRatioSettingsLayout != null
+ && mUserAspectRatioSettingsLayout.getTaskId() == taskId) {
+ mUserAspectRatioSettingsLayout.release();
+ mUserAspectRatioSettingsLayout = null;
+ }
}
private Context getOrCreateDisplayContext(int displayId) {
@@ -561,6 +650,10 @@
if (mActiveReachabilityEduLayout != null && condition.test(mActiveReachabilityEduLayout)) {
callback.accept(mActiveReachabilityEduLayout);
}
+ if (mUserAspectRatioSettingsLayout != null && condition.test(
+ mUserAspectRatioSettingsLayout)) {
+ callback.accept(mUserAspectRatioSettingsLayout);
+ }
}
/** An implementation of {@link OnInsetsChangedListener} for a given display id. */
@@ -595,4 +688,14 @@
insetsChanged(insetsState);
}
}
+
+ /**
+ * A class holding the state of the compat UI hints, which is shared between all compat UI
+ * window managers.
+ */
+ static class CompatUIHintsState {
+ boolean mHasShownSizeCompatHint;
+ boolean mHasShownCameraCompatHint;
+ boolean mHasShownUserAspectRatioSettingsButtonHint;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 065806d..ce3c509 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -38,6 +38,7 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIController.CompatUICallback;
+import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import java.util.function.Consumer;
@@ -235,15 +236,4 @@
return mCameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN
&& mCameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED;
}
-
- /**
- * A class holding the state of the compat UI hints, which is shared between all compat UI
- * window managers.
- */
- static class CompatUIHintsState {
- @VisibleForTesting
- boolean mHasShownSizeCompatHint;
- @VisibleForTesting
- boolean mHasShownCameraCompatHint;
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
index 95bb1fe..9de3f9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
@@ -36,6 +36,8 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import java.util.function.BiConsumer;
+
/**
* Window manager for the reachability education
*/
@@ -73,6 +75,8 @@
// we need to animate them.
private boolean mHasLetterboxSizeChanged;
+ private final BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> mOnDismissCallback;
+
@Nullable
@VisibleForTesting
ReachabilityEduLayout mLayout;
@@ -80,7 +84,8 @@
ReachabilityEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue,
ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
- CompatUIConfiguration compatUIConfiguration, ShellExecutor mainExecutor) {
+ CompatUIConfiguration compatUIConfiguration, ShellExecutor mainExecutor,
+ BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> onDismissCallback) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
@@ -89,6 +94,7 @@
mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight;
mCompatUIConfiguration = compatUIConfiguration;
mMainExecutor = mainExecutor;
+ mOnDismissCallback = onDismissCallback;
}
@Override
@@ -217,13 +223,17 @@
return;
}
final TaskInfo lastTaskInfo = getLastTaskInfo();
+ final boolean hasSeenHorizontalReachabilityEdu =
+ mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(lastTaskInfo);
+ final boolean hasSeenVerticalReachabilityEdu =
+ mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(lastTaskInfo);
final boolean eligibleForDisplayHorizontalEducation = mForceUpdate
- || !mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(lastTaskInfo)
+ || !hasSeenHorizontalReachabilityEdu
|| (mHasUserDoubleTapped
&& (mLetterboxHorizontalPosition == REACHABILITY_LEFT_OR_UP_POSITION
|| mLetterboxHorizontalPosition == REACHABILITY_RIGHT_OR_BOTTOM_POSITION));
final boolean eligibleForDisplayVerticalEducation = mForceUpdate
- || !mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(lastTaskInfo)
+ || !hasSeenVerticalReachabilityEdu
|| (mHasUserDoubleTapped
&& (mLetterboxVerticalPosition == REACHABILITY_LEFT_OR_UP_POSITION
|| mLetterboxVerticalPosition == REACHABILITY_RIGHT_OR_BOTTOM_POSITION));
@@ -239,6 +249,14 @@
if (!mHasLetterboxSizeChanged) {
updateHideTime();
mMainExecutor.executeDelayed(this::hideReachability, DISAPPEAR_DELAY_MS);
+ // If reachability education has been seen for the first time, trigger callback to
+ // display aspect ratio settings button once reachability education disappears
+ if (hasShownHorizontalReachabilityEduFirstTime(hasSeenHorizontalReachabilityEdu)
+ || hasShownVerticalReachabilityEduFirstTime(
+ hasSeenVerticalReachabilityEdu)) {
+ mMainExecutor.executeDelayed(this::triggerOnDismissCallback,
+ DISAPPEAR_DELAY_MS);
+ }
}
mHasUserDoubleTapped = false;
} else {
@@ -246,6 +264,38 @@
}
}
+ /**
+ * Compares the value of
+ * {@link CompatUIConfiguration#hasSeenHorizontalReachabilityEducation} before and after the
+ * layout is shown. Horizontal reachability education is considered seen for the first time if
+ * prior to viewing the layout,
+ * {@link CompatUIConfiguration#hasSeenHorizontalReachabilityEducation} is {@code false}
+ * but becomes {@code true} once the current layout is shown.
+ */
+ private boolean hasShownHorizontalReachabilityEduFirstTime(
+ boolean previouslyShownHorizontalReachabilityEducation) {
+ return !previouslyShownHorizontalReachabilityEducation
+ && mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(getLastTaskInfo());
+ }
+
+ /**
+ * Compares the value of
+ * {@link CompatUIConfiguration#hasSeenVerticalReachabilityEducation} before and after the
+ * layout is shown. Horizontal reachability education is considered seen for the first time if
+ * prior to viewing the layout,
+ * {@link CompatUIConfiguration#hasSeenVerticalReachabilityEducation} is {@code false}
+ * but becomes {@code true} once the current layout is shown.
+ */
+ private boolean hasShownVerticalReachabilityEduFirstTime(
+ boolean previouslyShownVerticalReachabilityEducation) {
+ return !previouslyShownVerticalReachabilityEducation
+ && mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(getLastTaskInfo());
+ }
+
+ private void triggerOnDismissCallback() {
+ mOnDismissCallback.accept(getLastTaskInfo(), getTaskListener());
+ }
+
private void hideReachability() {
if (mLayout == null || !shouldHideEducation()) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
new file mode 100644
index 0000000..5eeb3b6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
@@ -0,0 +1,136 @@
+/*
+ * 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.wm.shell.compatui;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Layout for the user aspect ratio button which opens the app list page in settings
+ * and allows users to change apps aspect ratio.
+ */
+public class UserAspectRatioSettingsLayout extends LinearLayout {
+
+ private static final float ALPHA_FULL_TRANSPARENT = 0f;
+
+ private static final float ALPHA_FULL_OPAQUE = 1f;
+
+ private static final long VISIBILITY_ANIMATION_DURATION_MS = 50;
+
+ private static final String ALPHA_PROPERTY_NAME = "alpha";
+
+ private UserAspectRatioSettingsWindowManager mWindowManager;
+
+ public UserAspectRatioSettingsLayout(Context context) {
+ this(context, null);
+ }
+
+ public UserAspectRatioSettingsLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public UserAspectRatioSettingsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public UserAspectRatioSettingsLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ void inject(@NonNull UserAspectRatioSettingsWindowManager windowManager) {
+ mWindowManager = windowManager;
+ }
+
+ void setUserAspectRatioSettingsHintVisibility(boolean show) {
+ setViewVisibility(R.id.user_aspect_ratio_settings_hint, show);
+ }
+
+ void setUserAspectRatioButtonVisibility(boolean show) {
+ setViewVisibility(R.id.user_aspect_ratio_settings_button, show);
+ // Hint should never be visible without button.
+ if (!show) {
+ setUserAspectRatioSettingsHintVisibility(/* show= */ false);
+ }
+ }
+
+ private void setViewVisibility(@IdRes int resId, boolean show) {
+ final View view = findViewById(resId);
+ int visibility = show ? View.VISIBLE : View.GONE;
+ if (view.getVisibility() == visibility) {
+ return;
+ }
+ if (show) {
+ showItem(view);
+ } else {
+ view.setVisibility(visibility);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ // Need to relayout after changes like hiding / showing a hint since they affect size.
+ // Doing this directly in setUserAspectRatioButtonVisibility can result in flaky animation.
+ mWindowManager.relayout();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ final ImageButton userAspectRatioButton =
+ findViewById(R.id.user_aspect_ratio_settings_button);
+ userAspectRatioButton.setOnClickListener(
+ view -> mWindowManager.onUserAspectRatioSettingsButtonClicked());
+ userAspectRatioButton.setOnLongClickListener(view -> {
+ mWindowManager.onUserAspectRatioSettingsButtonLongClicked();
+ return true;
+ });
+
+ final LinearLayout sizeCompatHint = findViewById(R.id.user_aspect_ratio_settings_hint);
+ ((TextView) sizeCompatHint.findViewById(R.id.compat_mode_hint_text))
+ .setText(R.string.user_aspect_ratio_settings_button_hint);
+ sizeCompatHint.setOnClickListener(
+ view -> setUserAspectRatioSettingsHintVisibility(/* show= */ false));
+ }
+
+ private void showItem(@NonNull View view) {
+ view.setVisibility(View.VISIBLE);
+ final ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, ALPHA_PROPERTY_NAME,
+ ALPHA_FULL_TRANSPARENT, ALPHA_FULL_OPAQUE);
+ fadeIn.setDuration(VISIBILITY_ANIMATION_DURATION_MS);
+ fadeIn.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setVisibility(View.VISIBLE);
+ }
+ });
+ fadeIn.start();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
new file mode 100644
index 0000000..bd53dc7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -0,0 +1,211 @@
+/*
+ * 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.wm.shell.compatui;
+
+import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Window manager for the user aspect ratio settings button which allows users to go to
+ * app settings and change apps aspect ratio.
+ */
+class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract {
+
+ private static final long SHOW_USER_ASPECT_RATIO_BUTTON_DELAY_MS = 500L;
+
+ private static final long HIDE_USER_ASPECT_RATIO_BUTTON_DELAY_MS = 4000L;
+
+ private long mNextButtonHideTimeMs = -1L;
+
+ private final BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> mOnButtonClicked;
+
+ private final ShellExecutor mShellExecutor;
+
+ @VisibleForTesting
+ @NonNull
+ final CompatUIHintsState mCompatUIHintsState;
+
+ @Nullable
+ private UserAspectRatioSettingsLayout mLayout;
+
+ // Remember the last reported states in case visibility changes due to keyguard or IME updates.
+ @VisibleForTesting
+ boolean mHasUserAspectRatioSettingsButton;
+
+ UserAspectRatioSettingsWindowManager(@NonNull Context context, @NonNull TaskInfo taskInfo,
+ @NonNull SyncTransactionQueue syncQueue,
+ @Nullable ShellTaskOrganizer.TaskListener taskListener,
+ @NonNull DisplayLayout displayLayout, @NonNull CompatUIHintsState compatUIHintsState,
+ @NonNull BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> onButtonClicked,
+ @NonNull ShellExecutor shellExecutor) {
+ super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mShellExecutor = shellExecutor;
+ mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
+ mCompatUIHintsState = compatUIHintsState;
+ mOnButtonClicked = onButtonClicked;
+ }
+
+ @Override
+ protected int getZOrder() {
+ return TASK_CHILD_LAYER_COMPAT_UI + 1;
+ }
+
+ @Override
+ protected @Nullable View getLayout() {
+ return mLayout;
+ }
+
+ @Override
+ protected void removeLayout() {
+ mLayout = null;
+ }
+
+ @Override
+ protected boolean eligibleToShowLayout() {
+ return mHasUserAspectRatioSettingsButton;
+ }
+
+ @Override
+ protected View createLayout() {
+ mLayout = inflateLayout();
+ mLayout.inject(this);
+
+ updateVisibilityOfViews();
+
+ return mLayout;
+ }
+
+ @VisibleForTesting
+ UserAspectRatioSettingsLayout inflateLayout() {
+ return (UserAspectRatioSettingsLayout) LayoutInflater.from(mContext).inflate(
+ R.layout.user_aspect_ratio_settings_layout, null);
+ }
+
+ @Override
+ public boolean updateCompatInfo(@NonNull TaskInfo taskInfo,
+ @NonNull ShellTaskOrganizer.TaskListener taskListener, boolean canShow) {
+ final boolean prevHasUserAspectRatioSettingsButton = mHasUserAspectRatioSettingsButton;
+ mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
+
+ if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
+ return false;
+ }
+
+ if (prevHasUserAspectRatioSettingsButton != mHasUserAspectRatioSettingsButton) {
+ updateVisibilityOfViews();
+ }
+ return true;
+ }
+
+ /** Called when the user aspect ratio settings button is clicked. */
+ void onUserAspectRatioSettingsButtonClicked() {
+ mOnButtonClicked.accept(getLastTaskInfo(), getTaskListener());
+ }
+
+ /** Called when the user aspect ratio settings button is long clicked. */
+ void onUserAspectRatioSettingsButtonLongClicked() {
+ if (mLayout == null) {
+ return;
+ }
+ mLayout.setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+ mNextButtonHideTimeMs = updateHideTime(HIDE_USER_ASPECT_RATIO_BUTTON_DELAY_MS);
+ mShellExecutor.executeDelayed(this::hideUserAspectRatioButton,
+ HIDE_USER_ASPECT_RATIO_BUTTON_DELAY_MS);
+ }
+
+ @Override
+ @VisibleForTesting
+ public void updateSurfacePosition() {
+ if (mLayout == null) {
+ return;
+ }
+ // Position of the button in the container coordinate.
+ final Rect taskBounds = getTaskBounds();
+ final Rect taskStableBounds = getTaskStableBounds();
+ final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
+ ? taskStableBounds.left - taskBounds.left
+ : taskStableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
+ final int positionY = taskStableBounds.bottom - taskBounds.top
+ - mLayout.getMeasuredHeight();
+ updateSurfacePosition(positionX, positionY);
+ }
+
+ @VisibleForTesting
+ void updateVisibilityOfViews() {
+ if (mHasUserAspectRatioSettingsButton) {
+ mShellExecutor.executeDelayed(this::showUserAspectRatioButton,
+ SHOW_USER_ASPECT_RATIO_BUTTON_DELAY_MS);
+ mNextButtonHideTimeMs = updateHideTime(HIDE_USER_ASPECT_RATIO_BUTTON_DELAY_MS);
+ mShellExecutor.executeDelayed(this::hideUserAspectRatioButton,
+ HIDE_USER_ASPECT_RATIO_BUTTON_DELAY_MS);
+ } else {
+ mShellExecutor.removeCallbacks(this::showUserAspectRatioButton);
+ mShellExecutor.execute(this::hideUserAspectRatioButton);
+ }
+ }
+
+ private void showUserAspectRatioButton() {
+ if (mLayout == null) {
+ return;
+ }
+ mLayout.setUserAspectRatioButtonVisibility(true);
+ // Only show by default for the first time.
+ if (!mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint) {
+ mLayout.setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+ mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint = true;
+ }
+ }
+
+ private void hideUserAspectRatioButton() {
+ if (mLayout == null || !isHideDelayReached(mNextButtonHideTimeMs)) {
+ return;
+ }
+ mLayout.setUserAspectRatioButtonVisibility(false);
+ }
+
+ private boolean isHideDelayReached(long nextHideTime) {
+ return SystemClock.uptimeMillis() >= nextHideTime;
+ }
+
+ private long updateHideTime(long hideDelay) {
+ return SystemClock.uptimeMillis() + hideDelay;
+ }
+
+ private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
+ return taskInfo.topActivityEligibleForUserAspectRatioButton
+ && (taskInfo.topActivityBoundsLetterboxed
+ || taskInfo.isUserFullscreenOverrideEnabled);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 1a84f4b..8df89bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -20,6 +20,7 @@
import android.app.ActivityTaskManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.SystemProperties;
import android.view.IWindowManager;
@@ -56,6 +57,7 @@
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.compatui.CompatUIConfiguration;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
@@ -319,6 +321,17 @@
return Optional.empty();
}
+ //
+ // PiP (optional feature)
+ //
+
+ @WMSingleton
+ @Provides
+ static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
+ PackageManager packageManager) {
+ return new PipUiEventLogger(uiEventLogger, packageManager);
+ }
+
//
// Bubbles (optional feature)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 9bf973f..5fd4f24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -32,6 +32,7 @@
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
@@ -49,7 +50,6 @@
import com.android.wm.shell.pip.PipTransition;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
index e8fae24..55a810a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
@@ -17,15 +17,12 @@
package com.android.wm.shell.dagger.pip;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Handler;
-import com.android.internal.logging.UiEventLogger;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
import dagger.Module;
import dagger.Provides;
@@ -49,11 +46,4 @@
static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
return new PipSurfaceTransactionHelper(context);
}
-
- @WMSingleton
- @Provides
- static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
- PackageManager packageManager) {
- return new PipUiEventLogger(uiEventLogger, packageManager);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index c7c6e8a..8dec4ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
+import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip2.PipTransition;
@@ -26,9 +27,9 @@
/**
* Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be
- * the successor of its sibling {@link Pip1SharedModule}.
+ * the successor of its sibling {@link Pip1Module}.
*/
-@Module
+@Module(includes = WMShellBaseModule.class)
public abstract class Pip2Module {
@WMSingleton
@Provides
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
index 80ffbb0..4e332be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
@@ -30,6 +30,7 @@
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.pip.LegacySizeSpecSource;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
@@ -43,7 +44,6 @@
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
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 1d46e75..633f627 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
@@ -18,6 +18,7 @@
import android.R
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -301,6 +302,24 @@
}
}
+ /** Move a desktop app to split screen. */
+ fun moveToSplit(task: RunningTaskInfo) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToSplit taskId=%d",
+ task.taskId
+ )
+ val wct = WindowContainerTransaction()
+ wct.setWindowingMode(task.token, WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW)
+ wct.setBounds(task.token, null)
+ wct.setDensityDpi(task.token, getDefaultDensityDpi())
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
/**
* The second part of the animated move to desktop transition, called after
* {@link startMoveToDesktop}. Move a task to fullscreen after being dragged from fullscreen
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 0d55018..296857b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -63,7 +63,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.view.Choreographer;
import android.view.Display;
import android.view.Surface;
@@ -83,6 +82,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -1735,17 +1735,13 @@
// animation.
// TODO(b/272819817): cleanup the null-check and extra logging.
final boolean hasTopActivityInfo = mTaskInfo.topActivityInfo != null;
- if (!hasTopActivityInfo) {
- ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
- "%s: TaskInfo.topActivityInfo is null", TAG);
- }
- if (SystemProperties.getBoolean(
- "persist.wm.debug.enable_pip_app_icon_overlay", true)
- && hasTopActivityInfo) {
+ if (hasTopActivityInfo) {
animator.setAppIconContentOverlay(
mContext, currentBounds, mTaskInfo.topActivityInfo,
mPipBoundsState.getLauncherState().getAppIconSizePx());
} else {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "%s: TaskInfo.topActivityInfo is null", TAG);
animator.setColorContentOverlay(mContext);
}
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 2563d98..db7e2c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -49,7 +49,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
-import android.os.SystemProperties;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -902,17 +901,13 @@
// animation.
// TODO(b/272819817): cleanup the null-check and extra logging.
final boolean hasTopActivityInfo = taskInfo.topActivityInfo != null;
- if (!hasTopActivityInfo) {
- ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
- "%s: TaskInfo.topActivityInfo is null", TAG);
- }
- if (SystemProperties.getBoolean(
- "persist.wm.debug.enable_pip_app_icon_overlay", true)
- && hasTopActivityInfo) {
+ if (hasTopActivityInfo) {
animator.setAppIconContentOverlay(
mContext, currentBounds, taskInfo.topActivityInfo,
mPipBoundsState.getLauncherState().getAppIconSizePx());
} else {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "%s: TaskInfo.topActivityInfo is null", TAG);
animator.setColorContentOverlay(mContext);
}
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
deleted file mode 100644
index 3e5a19b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip;
-
-import android.app.TaskInfo;
-import android.content.pm.PackageManager;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
-
-/**
- * Helper class that ends PiP log to UiEvent, see also go/uievent
- */
-public class PipUiEventLogger {
-
- private static final int INVALID_PACKAGE_UID = -1;
-
- private final UiEventLogger mUiEventLogger;
- private final PackageManager mPackageManager;
-
- private String mPackageName;
- private int mPackageUid = INVALID_PACKAGE_UID;
-
- public PipUiEventLogger(UiEventLogger uiEventLogger, PackageManager packageManager) {
- mUiEventLogger = uiEventLogger;
- mPackageManager = packageManager;
- }
-
- public void setTaskInfo(TaskInfo taskInfo) {
- if (taskInfo != null && taskInfo.topActivity != null) {
- mPackageName = taskInfo.topActivity.getPackageName();
- mPackageUid = getUid(mPackageName, taskInfo.userId);
- } else {
- mPackageName = null;
- mPackageUid = INVALID_PACKAGE_UID;
- }
- }
-
- /**
- * Sends log via UiEvent, reference go/uievent for how to debug locally
- */
- public void log(PipUiEventEnum event) {
- if (mPackageName == null || mPackageUid == INVALID_PACKAGE_UID) {
- return;
- }
- mUiEventLogger.log(event, mPackageUid, mPackageName);
- }
-
- private int getUid(String packageName, int userId) {
- int uid = INVALID_PACKAGE_UID;
- try {
- uid = mPackageManager.getApplicationInfoAsUser(
- packageName, 0 /* ApplicationInfoFlags */, userId).uid;
- } catch (PackageManager.NameNotFoundException e) {
- // do nothing.
- }
- return uid;
- }
-
- /**
- * Enums for logging the PiP events to UiEvent
- */
- public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "Activity enters picture-in-picture mode")
- PICTURE_IN_PICTURE_ENTER(603),
-
- @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
- PICTURE_IN_PICTURE_AUTO_ENTER(1313),
-
- @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
- PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
-
- @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
- PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
-
- @UiEvent(doc = "Removes picture-in-picture by tap close button")
- PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
-
- @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
- PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
-
- @UiEvent(doc = "Shows picture-in-picture menu")
- PICTURE_IN_PICTURE_SHOW_MENU(607),
-
- @UiEvent(doc = "Hides picture-in-picture menu")
- PICTURE_IN_PICTURE_HIDE_MENU(608),
-
- @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
- + " from previous Tron-based logging and currently not in use.")
- PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
-
- @UiEvent(doc = "User resize of the picture-in-picture window")
- PICTURE_IN_PICTURE_RESIZE(610),
-
- @UiEvent(doc = "User unstashed picture-in-picture")
- PICTURE_IN_PICTURE_STASH_UNSTASHED(709),
-
- @UiEvent(doc = "User stashed picture-in-picture to the left side")
- PICTURE_IN_PICTURE_STASH_LEFT(710),
-
- @UiEvent(doc = "User stashed picture-in-picture to the right side")
- PICTURE_IN_PICTURE_STASH_RIGHT(711),
-
- @UiEvent(doc = "User taps on the settings button in PiP menu")
- PICTURE_IN_PICTURE_SHOW_SETTINGS(933),
-
- @UiEvent(doc = "Closes PiP with app-provided close action")
- PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058);
-
- private final int mId;
-
- PipUiEventEnum(int id) {
- mId = id;
- }
-
- @Override
- public int getId() {
- return mId;
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index f9332e4..2d34035 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -40,6 +40,7 @@
"persist.wm.debug.enable_pip_keep_clear_algorithm_gravity", false);
protected int mKeepClearAreasPadding;
+ private int mImeOffset;
public PhonePipKeepClearAlgorithm(Context context) {
reloadResources(context);
@@ -48,6 +49,7 @@
private void reloadResources(Context context) {
final Resources res = context.getResources();
mKeepClearAreasPadding = res.getDimensionPixelSize(R.dimen.pip_keep_clear_areas_padding);
+ mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
}
/**
@@ -61,7 +63,7 @@
Rect insets = new Rect();
pipBoundsAlgorithm.getInsetBounds(insets);
if (pipBoundsState.isImeShowing()) {
- insets.bottom -= pipBoundsState.getImeHeight();
+ insets.bottom -= (pipBoundsState.getImeHeight() + mImeOffset);
}
// if PiP is stashed we only adjust the vertical position if it's outside of insets and
// ignore all keep clear areas, since it's already on the side
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 5e1b6be..c93d850 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -38,12 +38,12 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index b872267..f25110a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -123,14 +123,6 @@
private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
- private boolean mEnablePipKeepClearAlgorithm =
- SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
-
- @VisibleForTesting
- void setEnablePipKeepClearAlgorithm(boolean value) {
- mEnablePipKeepClearAlgorithm = value;
- }
-
private Context mContext;
protected ShellExecutor mMainExecutor;
private DisplayController mDisplayController;
@@ -166,10 +158,6 @@
// early bail out if the change was caused by keyguard showing up
return;
}
- if (!mEnablePipKeepClearAlgorithm) {
- // early bail out if the keep clear areas feature is disabled
- return;
- }
if (mPipBoundsState.isStashed()) {
// don't move when stashed
return;
@@ -187,10 +175,6 @@
}
private void updatePipPositionForKeepClearAreas() {
- if (!mEnablePipKeepClearAlgorithm) {
- // early bail out if the keep clear areas feature is disabled
- return;
- }
if (mIsKeyguardShowingOrAnimating) {
// early bail out if the change was caused by keyguard showing up
return;
@@ -343,19 +327,17 @@
public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
Set<Rect> unrestricted) {
if (mPipDisplayLayoutState.getDisplayId() == displayId) {
- if (mEnablePipKeepClearAlgorithm) {
- mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+ mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
- mMainExecutor.removeCallbacks(
- mMovePipInResponseToKeepClearAreasChangeCallback);
- mMainExecutor.executeDelayed(
- mMovePipInResponseToKeepClearAreasChangeCallback,
- PIP_KEEP_CLEAR_AREAS_DELAY);
+ mMainExecutor.removeCallbacks(
+ mMovePipInResponseToKeepClearAreasChangeCallback);
+ mMainExecutor.executeDelayed(
+ mMovePipInResponseToKeepClearAreasChangeCallback,
+ PIP_KEEP_CLEAR_AREAS_DELAY);
- ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "onKeepClearAreasChanged: restricted=%s, unrestricted=%s",
- restricted, unrestricted);
- }
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onKeepClearAreasChanged: restricted=%s, unrestricted=%s",
+ restricted, unrestricted);
}
}
};
@@ -660,25 +642,9 @@
// there's a keyguard present
return;
}
- int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
onDisplayChangedUncheck(mDisplayController
.getDisplayLayout(mPipDisplayLayoutState.getDisplayId()),
false /* saveRestoreSnapFraction */);
- int newMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
- if (!mEnablePipKeepClearAlgorithm) {
- // offset PiP to adjust for bottom inset change
- int pipTop = mPipBoundsState.getBounds().top;
- int diff = newMaxMovementBound - oldMaxMovementBound;
- if (diff < 0 && pipTop > newMaxMovementBound) {
- // bottom inset has increased, move PiP up if it is too low
- mPipMotionHelper.animateToOffset(mPipBoundsState.getBounds(),
- newMaxMovementBound - pipTop);
- }
- if (diff > 0 && oldMaxMovementBound == pipTop) {
- // bottom inset has decreased, move PiP down if it was by the edge
- mPipMotionHelper.animateToOffset(mPipBoundsState.getBounds(), diff);
- }
- }
}
});
@@ -947,14 +913,8 @@
* Sets both shelf visibility and its height.
*/
private void setShelfHeight(boolean visible, int height) {
- if (mEnablePipKeepClearAlgorithm) {
- // turn this into Launcher keep clear area registration instead
- setLauncherKeepClearAreaHeight(visible, height);
- return;
- }
- if (!mIsKeyguardShowingOrAnimating) {
- setShelfHeightLocked(visible, height);
- }
+ // turn this into Launcher keep clear area registration instead
+ setLauncherKeepClearAreaHeight(visible, height);
}
private void setLauncherKeepClearAreaHeight(boolean visible, int height) {
@@ -1015,16 +975,10 @@
private Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams,
int launcherRotation, Rect hotseatKeepClearArea) {
-
- if (mEnablePipKeepClearAlgorithm) {
- // preemptively add the keep clear area for Hotseat, so that it is taken into account
- // when calculating the entry destination bounds of PiP window
- mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
- hotseatKeepClearArea);
- } else {
- int shelfHeight = hotseatKeepClearArea.height();
- setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
- }
+ // preemptively add the keep clear area for Hotseat, so that it is taken into account
+ // when calculating the entry destination bounds of PiP window
+ mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
+ hotseatKeepClearArea);
onDisplayRotationChangedNotInPip(mContext, launcherRotation);
final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index da455f8..4e75847 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -38,7 +38,7 @@
import com.android.wm.shell.common.bubbles.DismissCircleView;
import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import kotlin.Unit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 779c539..837426a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -66,7 +66,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index b251f6f..8f0a8e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -33,7 +33,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.SystemProperties;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -48,19 +47,16 @@
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import java.util.function.Consumer;
-
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
+import java.util.function.Consumer;
+
/**
* A helper to animate and manipulate the PiP.
*/
public class PipMotionHelper implements PipAppOpsListener.Callback,
FloatingContentCoordinator.FloatingContent {
-
- public static final boolean ENABLE_FLING_TO_DISMISS_PIP =
- SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_pip", false);
private static final String TAG = "PipMotionHelper";
private static final boolean DEBUG = false;
@@ -707,7 +703,7 @@
loc[1] = animatedPipBounds.top;
}
};
- mMagnetizedPip.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_PIP);
+ mMagnetizedPip.setFlingToTargetEnabled(false);
}
return mMagnetizedPip;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index abe2db0..4e687dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -46,11 +46,11 @@
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipUiEventLogger;
import java.io.PrintWriter;
import java.util.function.Consumer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index ab65c9e..bfba4b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -34,7 +34,6 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.Size;
import android.view.DisplayCutout;
@@ -51,13 +50,13 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellInit;
@@ -73,14 +72,6 @@
private static final String TAG = "PipTouchHandler";
private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
- private boolean mEnablePipKeepClearAlgorithm =
- SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
-
- @VisibleForTesting
- void setEnablePipKeepClearAlgorithm(boolean value) {
- mEnablePipKeepClearAlgorithm = value;
- }
-
// Allow PIP to resize to a slightly bigger state upon touch
private boolean mEnableResize;
private final Context mContext;
@@ -430,48 +421,6 @@
mIsImeShowing ? mImeOffset : 0,
!mIsImeShowing && mIsShelfShowing ? mShelfHeight : 0);
- // If this is from an IME or shelf adjustment, then we should move the PiP so that it is not
- // occluded by the IME or shelf.
- if (fromImeAdjustment || fromShelfAdjustment) {
- if (mTouchState.isUserInteracting() && mTouchState.isDragging()) {
- // Defer the update of the current movement bounds until after the user finishes
- // touching the screen
- } else if (mEnablePipKeepClearAlgorithm) {
- // Ignore moving PiP if keep clear algorithm is enabled, since IME and shelf height
- // now are accounted for in the keep clear algorithm calculations
- } else {
- final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
- final Rect toMovementBounds = new Rect();
- mPipBoundsAlgorithm.getMovementBounds(curBounds, insetBounds,
- toMovementBounds, mIsImeShowing ? mImeHeight : 0);
- final int prevBottom = mPipBoundsState.getMovementBounds().bottom
- - mMovementBoundsExtraOffsets;
- // This is to handle landscape fullscreen IMEs, don't apply the extra offset in this
- // case
- final int toBottom = toMovementBounds.bottom < toMovementBounds.top
- ? toMovementBounds.bottom
- : toMovementBounds.bottom - extraOffset;
-
- if (isExpanded) {
- curBounds.set(mPipBoundsState.getExpandedBounds());
- mPipBoundsAlgorithm.getSnapAlgorithm().applySnapFraction(curBounds,
- toMovementBounds, mSavedSnapFraction);
- }
-
- if (prevBottom < toBottom) {
- // The movement bounds are expanding
- if (curBounds.top > prevBottom - mBottomOffsetBufferPx) {
- mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top);
- }
- } else if (prevBottom > toBottom) {
- // The movement bounds are shrinking
- if (curBounds.top > toBottom - mBottomOffsetBufferPx) {
- mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top);
- }
- }
- }
- }
-
// Update the movement bounds after doing the calculations based on the old movement bounds
// above
mPipBoundsState.setNormalMovementBounds(normalMovementBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 4819f66..dbec607 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -25,6 +25,7 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -35,7 +36,6 @@
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 2be7a49..29fff03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -71,6 +71,7 @@
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
@@ -200,6 +201,19 @@
@Override
public void setSplitScreenController(SplitScreenController splitScreenController) {
mSplitScreenController = splitScreenController;
+ mSplitScreenController.registerSplitScreenListener(new SplitScreen.SplitScreenListener() {
+ @Override
+ public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+ if (visible) {
+ DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
+ if (decor != null && DesktopModeStatus.isActive(mContext)
+ && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
+ mDesktopTasksController.ifPresent(c -> c.moveToSplit(decor.mTaskInfo));
+ }
+ }
+ }
+ });
}
@Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index a6501f0..efc69ebd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -58,6 +58,8 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import dagger.Lazy;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,8 +68,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import dagger.Lazy;
-
/**
* Tests for {@link CompatUIController}.
*
@@ -82,21 +82,36 @@
private CompatUIController mController;
private ShellInit mShellInit;
- private @Mock ShellController mMockShellController;
- private @Mock DisplayController mMockDisplayController;
- private @Mock DisplayInsetsController mMockDisplayInsetsController;
- private @Mock DisplayLayout mMockDisplayLayout;
- private @Mock DisplayImeController mMockImeController;
- private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
- private @Mock SyncTransactionQueue mMockSyncQueue;
- private @Mock ShellExecutor mMockExecutor;
- private @Mock Lazy<Transitions> mMockTransitionsLazy;
- private @Mock CompatUIWindowManager mMockCompatLayout;
- private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
- private @Mock RestartDialogWindowManager mMockRestartDialogLayout;
- private @Mock DockStateReader mDockStateReader;
- private @Mock CompatUIConfiguration mCompatUIConfiguration;
- private @Mock CompatUIShellCommandHandler mCompatUIShellCommandHandler;
+ @Mock
+ private ShellController mMockShellController;
+ @Mock
+ private DisplayController mMockDisplayController;
+ @Mock
+ private DisplayInsetsController mMockDisplayInsetsController;
+ @Mock
+ private DisplayLayout mMockDisplayLayout;
+ @Mock
+ private DisplayImeController mMockImeController;
+ @Mock
+ private ShellTaskOrganizer.TaskListener mMockTaskListener;
+ @Mock
+ private SyncTransactionQueue mMockSyncQueue;
+ @Mock
+ private ShellExecutor mMockExecutor;
+ @Mock
+ private Lazy<Transitions> mMockTransitionsLazy;
+ @Mock
+ private CompatUIWindowManager mMockCompatLayout;
+ @Mock
+ private LetterboxEduWindowManager mMockLetterboxEduLayout;
+ @Mock
+ private RestartDialogWindowManager mMockRestartDialogLayout;
+ @Mock
+ private DockStateReader mDockStateReader;
+ @Mock
+ private CompatUIConfiguration mCompatUIConfiguration;
+ @Mock
+ private CompatUIShellCommandHandler mCompatUIShellCommandHandler;
@Captor
ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index 5f294d5..3bce2b8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -44,7 +44,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
+import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import junit.framework.Assert;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 78c3cbd..4c837e6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -53,7 +53,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
+import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import junit.framework.Assert;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
index 973a99c..a802f15a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
@@ -40,6 +40,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.function.BiConsumer;
+
/**
* Tests for {@link ReachabilityEduWindowManager}.
*
@@ -57,6 +59,8 @@
private CompatUIConfiguration mCompatUIConfiguration;
@Mock
private DisplayLayout mDisplayLayout;
+ @Mock
+ private BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> mOnDismissCallback;
private TestShellExecutor mExecutor;
private TaskInfo mTaskInfo;
private ReachabilityEduWindowManager mWindowManager;
@@ -104,6 +108,7 @@
private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) {
return new ReachabilityEduWindowManager(mContext, taskInfo, mSyncTransactionQueue,
- mTaskListener, mDisplayLayout, mCompatUIConfiguration, mExecutor);
+ mTaskListener, mDisplayLayout, mCompatUIConfiguration, mExecutor,
+ mOnDismissCallback);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
new file mode 100644
index 0000000..1fee153
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.wm.shell.compatui;
+
+import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.app.TaskInfo.CameraCompatControlState;
+import android.content.ComponentName;
+import android.testing.AndroidTestingRunner;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.SurfaceControlViewHost;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Tests for {@link UserAspectRatioSettingsLayout}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:UserAspectRatioSettingsLayoutTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class UserAspectRatioSettingsLayoutTest extends ShellTestCase {
+
+ private static final int TASK_ID = 1;
+
+ @Mock
+ private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock
+ private BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener>
+ mOnUserAspectRatioSettingsButtonClicked;
+ @Mock
+ private ShellTaskOrganizer.TaskListener mTaskListener;
+ @Mock
+ private SurfaceControlViewHost mViewHost;
+ @Captor
+ private ArgumentCaptor<ShellTaskOrganizer.TaskListener> mUserAspectRatioTaskListenerCaptor;
+ @Captor
+ private ArgumentCaptor<TaskInfo> mUserAspectRationTaskInfoCaptor;
+
+ private UserAspectRatioSettingsWindowManager mWindowManager;
+ private UserAspectRatioSettingsLayout mLayout;
+ private TaskInfo mTaskInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
+ mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
+ mSyncTransactionQueue, mTaskListener, new DisplayLayout(),
+ new CompatUIController.CompatUIHintsState(),
+ mOnUserAspectRatioSettingsButtonClicked, new TestShellExecutor());
+
+ mLayout = (UserAspectRatioSettingsLayout) LayoutInflater.from(mContext).inflate(
+ R.layout.user_aspect_ratio_settings_layout, null);
+ mLayout.inject(mWindowManager);
+
+ spyOn(mWindowManager);
+ spyOn(mLayout);
+ doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
+ doReturn(mLayout).when(mWindowManager).inflateLayout();
+ }
+
+ @Test
+ public void testOnClickForUserAspectRatioSettingsButton() {
+ final ImageButton button = mLayout.findViewById(R.id.user_aspect_ratio_settings_button);
+ button.performClick();
+
+ verify(mWindowManager).onUserAspectRatioSettingsButtonClicked();
+ verify(mOnUserAspectRatioSettingsButtonClicked).accept(
+ mUserAspectRationTaskInfoCaptor.capture(),
+ mUserAspectRatioTaskListenerCaptor.capture());
+ final Pair<TaskInfo, ShellTaskOrganizer.TaskListener> result =
+ new Pair<>(mUserAspectRationTaskInfoCaptor.getValue(),
+ mUserAspectRatioTaskListenerCaptor.getValue());
+ Assert.assertEquals(mTaskInfo, result.first);
+ Assert.assertEquals(mTaskListener, result.second);
+ }
+
+ @Test
+ public void testOnLongClickForUserAspectRatioButton() {
+ doNothing().when(mWindowManager).onUserAspectRatioSettingsButtonLongClicked();
+
+ final ImageButton button = mLayout.findViewById(R.id.user_aspect_ratio_settings_button);
+ button.performLongClick();
+
+ verify(mWindowManager).onUserAspectRatioSettingsButtonLongClicked();
+ }
+
+ @Test
+ public void testOnClickForUserAspectRatioSettingsHint() {
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.createLayout(/* canShow= */ true);
+ final LinearLayout sizeCompatHint = mLayout.findViewById(
+ R.id.user_aspect_ratio_settings_hint);
+ sizeCompatHint.performClick();
+
+ verify(mLayout).setUserAspectRatioSettingsHintVisibility(/* show= */ false);
+ }
+
+ private static TaskInfo createTaskInfo(boolean hasSizeCompat,
+ @CameraCompatControlState int cameraCompatControlState) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = TASK_ID;
+ taskInfo.topActivityInSizeCompat = hasSizeCompat;
+ taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
new file mode 100644
index 0000000..b48538c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -0,0 +1,350 @@
+/*
+ * 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.wm.shell.compatui;
+
+import static android.view.WindowInsets.Type.navigationBars;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.util.Pair;
+import android.view.DisplayInfo;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * Tests for {@link UserAspectRatioSettingsWindowManager}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:UserAspectRatioSettingsWindowManagerTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
+
+ private static final int TASK_ID = 1;
+
+ @Mock private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock
+ private BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener>
+ mOnUserAspectRatioSettingsButtonClicked;
+ @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
+ @Mock private UserAspectRatioSettingsLayout mLayout;
+ @Mock private SurfaceControlViewHost mViewHost;
+ @Captor
+ private ArgumentCaptor<ShellTaskOrganizer.TaskListener> mUserAspectRatioTaskListenerCaptor;
+ @Captor
+ private ArgumentCaptor<TaskInfo> mUserAspectRationTaskInfoCaptor;
+
+ private final Set<String> mPackageNameCache = new HashSet<>();
+
+ private UserAspectRatioSettingsWindowManager mWindowManager;
+ private TaskInfo mTaskInfo;
+
+ private TestShellExecutor mExecutor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mExecutor = new TestShellExecutor();
+ mTaskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ false, /* topActivityBoundsLetterboxed */ true);
+ mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
+ mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+ mOnUserAspectRatioSettingsButtonClicked, mExecutor);
+ spyOn(mWindowManager);
+ doReturn(mLayout).when(mWindowManager).inflateLayout();
+ doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
+ }
+
+ @Test
+ public void testCreateUserAspectRatioButton() {
+ // Doesn't create layout if show is false.
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ assertTrue(mWindowManager.createLayout(/* canShow= */ false));
+
+ verify(mWindowManager, never()).inflateLayout();
+
+ // Doesn't create hint popup.
+ mWindowManager.mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint = true;
+ assertTrue(mWindowManager.createLayout(/* canShow= */ true));
+
+ verify(mWindowManager).inflateLayout();
+ mExecutor.flushAll();
+ verify(mLayout).setUserAspectRatioButtonVisibility(/* show= */ true);
+ verify(mLayout, never()).setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+
+ // Creates hint popup.
+ clearInvocations(mWindowManager);
+ clearInvocations(mLayout);
+ mWindowManager.release();
+ mWindowManager.mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint = false;
+ assertTrue(mWindowManager.createLayout(/* canShow= */ true));
+
+ verify(mWindowManager).inflateLayout();
+ assertNotNull(mLayout);
+ mExecutor.flushAll();
+ verify(mLayout).setUserAspectRatioButtonVisibility(/* show= */ true);
+ verify(mLayout).setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+ assertTrue(mWindowManager.mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint);
+
+ // Returns false and doesn't create layout if mHasUserAspectRatioSettingsButton is false.
+ clearInvocations(mWindowManager);
+ mWindowManager.release();
+ mWindowManager.mHasUserAspectRatioSettingsButton = false;
+ assertFalse(mWindowManager.createLayout(/* canShow= */ true));
+
+ verify(mWindowManager, never()).inflateLayout();
+ }
+
+ @Test
+ public void testRelease() {
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.createLayout(/* canShow= */ true);
+
+ verify(mWindowManager).inflateLayout();
+
+ mWindowManager.release();
+
+ verify(mViewHost).release();
+ }
+
+ @Test
+ public void testUpdateCompatInfo() {
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.createLayout(/* canShow= */ true);
+
+ // No diff
+ clearInvocations(mWindowManager);
+ TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true);
+ assertTrue(mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true));
+
+ verify(mWindowManager, never()).updateSurfacePosition();
+ verify(mWindowManager, never()).release();
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+
+
+ // Change task listener, recreate button.
+ clearInvocations(mWindowManager);
+ final ShellTaskOrganizer.TaskListener newTaskListener = mock(
+ ShellTaskOrganizer.TaskListener.class);
+ assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+
+ verify(mWindowManager).release();
+ verify(mWindowManager).createLayout(/* canShow= */ true);
+
+ // Change has eligibleForUserAspectRatioButton to false, dispose the component
+ clearInvocations(mWindowManager);
+ clearInvocations(mLayout);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ false, /* topActivityBoundsLetterboxed */ true);
+ assertFalse(
+ mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+ verify(mWindowManager).release();
+ }
+
+ @Test
+ public void testUpdateCompatInfoLayoutNotInflatedYet() {
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.createLayout(/* canShow= */ false);
+
+ verify(mWindowManager, never()).inflateLayout();
+
+ // Change topActivityInSizeCompat to false and pass canShow true, layout shouldn't be
+ // inflated
+ clearInvocations(mWindowManager);
+ TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ false, /* topActivityBoundsLetterboxed */ true);
+ mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+
+ verify(mWindowManager, never()).inflateLayout();
+
+ // Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated.
+ clearInvocations(mWindowManager);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true);
+ mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+
+ verify(mWindowManager).inflateLayout();
+ }
+
+ @Test
+ public void testUpdateDisplayLayout() {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ final DisplayLayout displayLayout1 = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
+
+ mWindowManager.updateDisplayLayout(displayLayout1);
+ verify(mWindowManager).updateSurfacePosition();
+
+ // No update if the display bounds is the same.
+ clearInvocations(mWindowManager);
+ final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
+ mWindowManager.updateDisplayLayout(displayLayout2);
+ verify(mWindowManager, never()).updateSurfacePosition();
+ }
+
+ @Test
+ public void testUpdateDisplayLayoutInsets() {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
+
+ mWindowManager.updateDisplayLayout(displayLayout);
+ verify(mWindowManager).updateSurfacePosition();
+
+ // Update if the insets change on the existing display layout
+ clearInvocations(mWindowManager);
+ InsetsState insetsState = new InsetsState();
+ insetsState.setDisplayFrame(new Rect(0, 0, 1000, 2000));
+ InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+ insetsSource.setFrame(0, 1800, 1000, 2000);
+ insetsState.addSource(insetsSource);
+ displayLayout.setInsets(mContext.getResources(), insetsState);
+ mWindowManager.updateDisplayLayout(displayLayout);
+ verify(mWindowManager).updateSurfacePosition();
+ }
+
+ @Test
+ public void testUpdateVisibility() {
+ // Create button if it is not created.
+ mWindowManager.removeLayout();
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.updateVisibility(/* canShow= */ true);
+
+ verify(mWindowManager).createLayout(/* canShow= */ true);
+
+ // Hide button.
+ clearInvocations(mWindowManager);
+ doReturn(View.VISIBLE).when(mLayout).getVisibility();
+ mWindowManager.updateVisibility(/* canShow= */ false);
+
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+ verify(mLayout).setVisibility(View.GONE);
+
+ // Show button.
+ doReturn(View.GONE).when(mLayout).getVisibility();
+ mWindowManager.updateVisibility(/* canShow= */ true);
+
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+ verify(mLayout).setVisibility(View.VISIBLE);
+ }
+
+ @Test
+ public void testAttachToParentSurface() {
+ final SurfaceControl.Builder b = new SurfaceControl.Builder();
+ mWindowManager.attachToParentSurface(b);
+
+ verify(mTaskListener).attachChildSurfaceToTask(TASK_ID, b);
+ }
+
+ @Test
+ public void testOnUserAspectRatioButtonClicked() {
+ mWindowManager.onUserAspectRatioSettingsButtonClicked();
+
+ verify(mOnUserAspectRatioSettingsButtonClicked).accept(
+ mUserAspectRationTaskInfoCaptor.capture(),
+ mUserAspectRatioTaskListenerCaptor.capture());
+ final Pair<TaskInfo, ShellTaskOrganizer.TaskListener> result =
+ new Pair<>(mUserAspectRationTaskInfoCaptor.getValue(),
+ mUserAspectRatioTaskListenerCaptor.getValue());
+ Assert.assertEquals(mTaskInfo, result.first);
+ Assert.assertEquals(mTaskListener, result.second);
+ }
+
+ @Test
+ public void testOnUserAspectRatioButtonLongClicked_showHint() {
+ // Not create hint popup.
+ mWindowManager.mHasUserAspectRatioSettingsButton = true;
+ mWindowManager.mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint = true;
+ mWindowManager.createLayout(/* canShow= */ true);
+
+ verify(mWindowManager).inflateLayout();
+ verify(mLayout, never()).setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+
+ mWindowManager.onUserAspectRatioSettingsButtonLongClicked();
+
+ verify(mLayout).setUserAspectRatioSettingsHintVisibility(/* show= */ true);
+ }
+
+ @Test
+ public void testWhenDockedStateHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ newTaskInfo.configuration.uiMode |= Configuration.UI_MODE_TYPE_DESK;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
+ }
+
+ private static TaskInfo createTaskInfo(boolean eligibleForUserAspectRatioButton,
+ boolean topActivityBoundsLetterboxed) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = TASK_ID;
+ taskInfo.topActivityEligibleForUserAspectRatioButton = eligibleForUserAspectRatioButton;
+ taskInfo.topActivityBoundsLetterboxed = topActivityBoundsLetterboxed;
+ taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
+ taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 1e3fe42..248d665 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -53,6 +53,7 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 0ae2908..05c6ba9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -76,7 +76,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
@@ -329,21 +328,7 @@
}
@Test
- public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() {
- mPipController.setEnablePipKeepClearAlgorithm(false);
- final int displayId = 1;
- final Rect keepClearArea = new Rect(0, 0, 10, 10);
- when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId);
-
- mPipController.mDisplaysChangedListener.onKeepClearAreasChanged(
- displayId, Set.of(keepClearArea), Set.of());
-
- verify(mMockPipBoundsState, never()).setKeepClearAreas(Mockito.anySet(), Mockito.anySet());
- }
-
- @Test
- public void onKeepClearAreasChanged_featureEnabled_updatesPipBoundsState() {
- mPipController.setEnablePipKeepClearAlgorithm(true);
+ public void onKeepClearAreasChanged_updatesPipBoundsState() {
final int displayId = 1;
final Rect keepClearArea = new Rect(0, 0, 10, 10);
when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 689b5c5..12b4f3e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -37,6 +37,7 @@
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -45,7 +46,6 @@
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 852183c..314f195d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,6 +33,7 @@
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -42,7 +42,6 @@
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.sysui.ShellInit;
import org.junit.Before;
@@ -174,16 +173,4 @@
verify(mPipResizeGestureHandler, times(1))
.updateMaxSize(expectedMaxSize.getWidth(), expectedMaxSize.getHeight());
}
-
- @Test
- public void updateMovementBounds_withImeAdjustment_movesPip() {
- mPipTouchHandler.setEnablePipKeepClearAlgorithm(false);
- mFromImeAdjustment = true;
- mPipTouchHandler.onImeVisibilityChanged(true /* imeVisible */, mImeHeight);
-
- mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mPipBounds, mCurBounds,
- mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
-
- verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt());
- }
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e8c9d0d..c3087bc 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6915,7 +6915,10 @@
/**
* @hide
- * Returns whether CSD is enabled and supported by the HAL on this device.
+ * Returns whether CSD is enabled and supported by the current active audio module HAL.
+ * This method will return {@code false) for setups in which CSD as a feature is available
+ * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see
+ * {@link AudioManager#isCsdAsAFeatureEnabled()}).
*/
@TestApi
@RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
@@ -6929,6 +6932,49 @@
/**
* @hide
+ * Returns whether CSD as a feature can be manipulated by a client. This method
+ * returns {@code true} in countries where there isn't a safe hearing regulation
+ * enforced.
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public boolean isCsdAsAFeatureAvailable() {
+ try {
+ return getService().isCsdAsAFeatureAvailable();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Returns {@code true} if the client has enabled CSD. This function should only
+ * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public boolean isCsdAsAFeatureEnabled() {
+ try {
+ return getService().isCsdAsAFeatureEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Enables/disables the CSD feature. This function should only be called if
+ * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setCsdAsAFeatureEnabled(boolean csdToggleValue) {
+ try {
+ getService().setCsdAsAFeatureEnabled(csdToggleValue);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
* Describes an audio device that has not been categorized with a specific
* audio type.
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 180c7fd..9d62e37 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -323,6 +323,15 @@
boolean isCsdEnabled();
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ boolean isCsdAsAFeatureAvailable();
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ boolean isCsdAsAFeatureEnabled();
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ oneway void setCsdAsAFeatureEnabled(boolean csdToggleValue);
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
oneway void setBluetoothAudioDeviceCategory(in String address, boolean isBle, int deviceType);
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 42eaf00..15a668a 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -33,7 +33,7 @@
<string name="passwordless_technology_detail" msgid="6853928846532955882">"借助通行密钥,您不必依赖密码就能登录。您只需使用指纹、人脸识别功能、PIN 码或滑动图案便可验证您的身份并创建通行密钥。"</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"公钥加密"</string>
<string name="public_key_cryptography_detail" msgid="6937631710280562213">"根据 FIDO 联盟(成员包括 Google、Apple、Microsoft 等)和 W3C 的标准,通行密钥使用加密密钥对。不同于“用户名+密码字符串”的传统登录凭据,采用通行密钥时,系统会为应用或网站创建一个私钥-公钥对。私钥会安全地存储在您的设备上或密码管理工具中,用于证实您的身份。公钥会被共享给应用或网站服务器。您只要使用相应密钥,就能瞬间注册并登录。"</string>
- <string name="improved_account_security_title" msgid="1069841917893513424">"提升了帐号安全性"</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"提升了账号安全性"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"每个密钥都是专为特定应用或网站创建的,且仅与各自对应的网站或应用关联,因此您绝不会错误地登录任何欺诈性应用或网站。另外,由于服务器只保留公钥,黑客入侵的难度会大大增加。"</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"无缝转换"</string>
<string name="seamless_transition_detail" msgid="4475509237171739843">"在我们向无密码未来迈进的过程中,密码仍会与通行密钥并行使用。"</string>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index 3f5da11..e3196c0 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (бяспечны)"</item>
<item msgid="7322156123728520872">"4K (шырокамаштабны)"</item>
<item msgid="7735692090314849188">"4K (шырокамаштабны, бяспечны)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (два экраны)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Няма"</item>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 17d5e1d..f971d3c 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (segurua)"</item>
<item msgid="7322156123728520872">"4K (hobetua)"</item>
<item msgid="7735692090314849188">"4K (hobetua, segurua)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (bi pantaila)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Bat ere ez"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 3fb1833..032768a 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (sécurisé)"</item>
<item msgid="7322156123728520872">"4K (adapté à la haute résolution)"</item>
<item msgid="7735692090314849188">"4K (adapté haute rés., sécurisé)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (double écran)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Aucun"</item>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index e33c759..9e58b90 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (સુરક્ષિત)"</item>
<item msgid="7322156123728520872">"4K (ઉચ્ચ સ્તરીય)"</item>
<item msgid="7735692090314849188">"4K (ઉચ્ચ સ્તરીય, સુરક્ષિત)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (દ્વિ સ્ક્રીન)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"કોઈ નહીં"</item>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 95aeee7..edd8f29 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (aman)"</item>
<item msgid="7322156123728520872">"4K (ditingkatkan)"</item>
<item msgid="7735692090314849188">"4K (ditingkatkan, aman)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (layar ganda)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Tidak ada"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 5926a6b..79151a3 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -545,12 +545,12 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Chiedi ogni volta"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Fino alla disattivazione"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
- <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo telefono"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Questo tablet"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
- <string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
+ <string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo smartphone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossibile riprodurre su questo dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Esegui l\'upgrade dell\'account per cambiare"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Qui non è possibile riprodurre i download"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 51bda70..ee5b81d 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -316,7 +316,7 @@
<string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"יש לבחור תצורת USB"</string>
<string name="allow_mock_location" msgid="2102650981552527884">"אפשרות של מיקומים מדומים"</string>
<string name="allow_mock_location_summary" msgid="179780881081354579">"אפשרות של מיקומים מדומים"</string>
- <string name="debug_view_attributes" msgid="3539609843984208216">"לאפשר בדיקת תכונת תצוגה"</string>
+ <string name="debug_view_attributes" msgid="3539609843984208216">"לאפשר את הבדיקה של מאפיינים של ה-View"</string>
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"השארת חבילת הגלישה פעילה תמיד, גם כש-Wi‑Fi פעיל (למעבר מהיר בין רשתות)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"אם השירות זמין, יש להשתמש בשיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"לאפשר ניפוי באגים של USB?"</string>
@@ -343,7 +343,7 @@
<string name="select_application" msgid="2543228890535466325">"בחירת אפליקציה"</string>
<string name="no_application" msgid="9038334538870247690">"אף אחת"</string>
<string name="wait_for_debugger" msgid="7461199843335409809">"יש להמתין לכלי לניפוי באגים"</string>
- <string name="wait_for_debugger_summary" msgid="6846330006113363286">"אפליקציה שנוקו בה הבאגים ממתינה למנקה הבאגים לצירוף לפני ביצוע"</string>
+ <string name="wait_for_debugger_summary" msgid="6846330006113363286">"האפליקציה שמתבצע בה ניקוי באגים ממתינה שהכלי לניפוי באגים יתחבר אליה לפני הריצה"</string>
<string name="debug_input_category" msgid="7349460906970849771">"קלט"</string>
<string name="debug_drawing_category" msgid="5066171112313666619">"שרטוט"</string>
<string name="debug_hw_drawing_category" msgid="5830815169336975162">"עיבוד מואץ של חומרה"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index 2c7ac98..bd3043d 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4 KB (drošs)"</item>
<item msgid="7322156123728520872">"4 KB (mērogots)"</item>
<item msgid="7735692090314849188">"4 KB (mērogots, drošs)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (dubults ekrāns)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Nav"</item>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index c364c58..470f0c0 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (sikker)"</item>
<item msgid="7322156123728520872">"4K (oppskalert)"</item>
<item msgid="7735692090314849188">"4K (oppskalert, sikker)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (dobbel skjerm)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Ingen"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index dc68bf3..598304b 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -556,7 +556,7 @@
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan ikke spille av nedlastinger her"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Prøv igjen etter annonsen"</string>
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vekk enheten for å spille her"</string>
- <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten er ikke godkjent"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten er ikke godkjent til å spille av"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan ikke spille av dette her"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index b8e945f..818347e 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (veilig)"</item>
<item msgid="7322156123728520872">"4K (opgeschaald)"</item>
<item msgid="7735692090314849188">"4K (opgeschaald, veilig)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (dubbel scherm)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (dual screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Geen"</item>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index 4f58a3c..3c4ab20 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (ਸੁਰੱਖਿਅਤ)"</item>
<item msgid="7322156123728520872">"4K (ਪੂਰਾ ਕੀਤਾ)"</item>
<item msgid="7735692090314849188">"4K (ਪੂਰਾ ਕੀਤਾ, ਸੁਰੱਖਿਅਤ)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (ਦੂਹਰੀ ਸਕ੍ਰੀਨ)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"ਕੋਈ ਨਹੀਂ"</item>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index c1bb31e..9f60cd7 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (защита)"</item>
<item msgid="7322156123728520872">"4K (масштабирование)"</item>
<item msgid="7735692090314849188">"4K (масштабирование, защита)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (два экрана)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Нет"</item>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index daaa138..e6cb1d6 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (säkert)"</item>
<item msgid="7322156123728520872">"4K (uppskalat)"</item>
<item msgid="7735692090314849188">"4K (uppskalat, säkert)"</item>
- <item msgid="7346816300608639624">"720 p, 1080 p (dubbla skärmar)"</item>
+ <item msgid="7346816300608639624">"720 p, 1080 p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Inga"</item>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index b66fe5c..6d4d3a9 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (ปลอดภัย)"</item>
<item msgid="7322156123728520872">"4K (เพิ่มความละเอียด)"</item>
<item msgid="7735692090314849188">"4K (เพิ่มความละเอียด ปลอดภัย)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (หน้าจอคู่)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"ไม่มี"</item>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index e22ad90..e8b26df 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (güvenli)"</item>
<item msgid="7322156123728520872">"4K (yukarı ölçeklenmiş)"</item>
<item msgid="7735692090314849188">"4K (yukarı ölçeklenmiş, güvenli)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (çift ekran)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Hiçbiri"</item>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index dc02eeb..cc64acc 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K (захист)"</item>
<item msgid="7322156123728520872">"4K (масштабування)"</item>
<item msgid="7735692090314849188">"4K (масштабування, захист)"</item>
- <item msgid="7346816300608639624">"720p, 1080p (два екрани)"</item>
+ <item msgid="7346816300608639624">"720p, 1080p (Dual Screen)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"Нічого"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 679098a..9312b2e 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -243,7 +243,7 @@
<item msgid="8612549335720461635">"4K(安全)"</item>
<item msgid="7322156123728520872">"4K(画质提升)"</item>
<item msgid="7735692090314849188">"4K(画质提升、安全)"</item>
- <item msgid="7346816300608639624">"720p,1080p(双屏)"</item>
+ <item msgid="7346816300608639624">"720p、1080p(双屏幕)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="4433736508877934305">"无"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index fabc004..ab16a73 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -552,7 +552,7 @@
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"无法在此设备上播放"</string>
- <string name="media_output_status_require_premium" msgid="8411255800047014822">"升级帐号后才能切换"</string>
+ <string name="media_output_status_require_premium" msgid="8411255800047014822">"升级账号后才能切换"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"无法在此设备上播放下载的内容"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"广告之后重试"</string>
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"若要在此设备上播放,请唤醒设备"</string>
@@ -576,7 +576,7 @@
<string name="delete_blob_text" msgid="2819192607255625697">"删除共享数据"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"确定要删除这些共享数据吗?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"用户拥有个人专属的应用和内容"</string>
- <string name="user_add_profile_item_summary" msgid="5418602404308968028">"您可以限制其他人使用来自您的帐号的应用和内容"</string>
+ <string name="user_add_profile_item_summary" msgid="5418602404308968028">"您可以限制其他人使用来自您的账号的应用和内容"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"用户"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"受限个人资料"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"要添加新用户吗?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index 9ab84d2..f90a17a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -45,6 +45,7 @@
private static final int EXTREME_LOW_BATTERY_THRESHOLD = 3;
private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
+ public static final int BATTERY_LEVEL_UNKNOWN = -1;
public static final int CHARGING_UNKNOWN = -1;
public static final int CHARGING_SLOWLY = 0;
public static final int CHARGING_REGULAR = 1;
@@ -186,12 +187,13 @@
/** Gets the battery level from the intent. */
public static int getBatteryLevel(Intent batteryChangedIntent) {
if (batteryChangedIntent == null) {
- return -1; /*invalid battery level*/
+ return BATTERY_LEVEL_UNKNOWN;
}
- final int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ final int level =
+ batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL_UNKNOWN);
final int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
return scale == 0
- ? -1 /*invalid battery level*/
+ ? BATTERY_LEVEL_UNKNOWN
: Math.round((level / (float) scale) * 100f);
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3efb41d..c2dbf98 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -240,6 +240,7 @@
Settings.Secure.HEARING_AID_CALL_ROUTING,
Settings.Secure.HEARING_AID_MEDIA_ROUTING,
Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
- Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+ Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index f6c2f69..a49461e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -198,6 +198,7 @@
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_TOUCH_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
@@ -259,6 +260,8 @@
VALIDATORS.put(Secure.NAV_BAR_KIDS_MODE, BOOLEAN_VALIDATOR);
VALIDATORS.put(
Secure.NAVIGATION_MODE, new DiscreteValueValidator(new String[] {"0", "1", "2"}));
+ VALIDATORS.put(Secure.NAVIGATION_MODE_RESTORE,
+ new DiscreteValueValidator(new String[] {"-1", "0", "1", "2"}));
VALIDATORS.put(Secure.BACK_GESTURE_INSET_SCALE_LEFT,
new InclusiveFloatRangeValidator(0.0f, Float.MAX_VALUE));
VALIDATORS.put(Secure.BACK_GESTURE_INSET_SCALE_RIGHT,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 11154d1..056be2e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -813,7 +813,11 @@
continue;
}
- if (settingsToPreserve.contains(getQualifiedKeyForSetting(key, contentUri))) {
+ // Filter out Settings.Secure.NAVIGATION_MODE from modified preserve settings.
+ // Let it take part in restore process. See also b/244532342.
+ boolean isSettingPreserved = settingsToPreserve.contains(
+ getQualifiedKeyForSetting(key, contentUri));
+ if (isSettingPreserved && !Settings.Secure.NAVIGATION_MODE.equals(key)) {
Log.i(TAG, "Skipping restore for setting " + key + " as it is marked as "
+ "preserved");
continue;
@@ -874,6 +878,23 @@
} else {
destination = contentUri;
}
+
+ // Value is written to NAVIGATION_MODE_RESTORE to mark navigation mode
+ // has been set before on source device.
+ // See also: b/244532342.
+ if (Settings.Secure.NAVIGATION_MODE.equals(key)) {
+ contentValues.clear();
+ contentValues.put(Settings.NameValueTable.NAME,
+ Settings.Secure.NAVIGATION_MODE_RESTORE);
+ contentValues.put(Settings.NameValueTable.VALUE, value);
+ cr.insert(destination, contentValues);
+ // Avoid restore original setting if it has been preserved.
+ if (isSettingPreserved) {
+ Log.i(TAG, "Skipping restore for setting navigation_mode "
+ + "as it is marked as preserved");
+ continue;
+ }
+ }
settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
mRestoredFromSdkInt);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a83bfda..ef4e84f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1926,6 +1926,9 @@
dumpSetting(s, p,
Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED,
SecureSettingsProto.Assist.LONG_PRESS_HOME_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
+ SecureSettingsProto.Assist.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED);
p.end(assistToken);
final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 5583384..91c72b5 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -703,7 +703,8 @@
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
Settings.Secure.ATTENTIVE_TIMEOUT,
- Settings.Secure.AUDIO_DEVICE_INVENTORY, // setting not controllable by user
+ Settings.Secure.AUDIO_DEVICE_INVENTORY, // not controllable by user
+ Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED, // not controllable by user
Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION,
Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT,
Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE,
@@ -848,7 +849,8 @@
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
Settings.Secure.UI_TRANSLATION_ENABLED,
Settings.Secure.CREDENTIAL_SERVICE,
- Settings.Secure.CREDENTIAL_SERVICE_PRIMARY);
+ Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
+ Settings.Secure.NAVIGATION_MODE_RESTORE);
@Test
public void systemSettingsBackedUpOrDenied() {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 889c026..dd71dfa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -48,6 +48,7 @@
Column(
modifier =
modifier
+ .element(key = Notifications.Elements.Notifications)
.fillMaxWidth()
.defaultMinSize(minHeight = 300.dp)
.clip(RoundedCornerShape(32.dp))
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
index 38712b0..291617f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
@@ -1,11 +1,12 @@
package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.systemui.scene.ui.composable.QuickSettings
fun TransitionBuilder.goneToQuickSettingsTransition() {
spec = tween(durationMillis = 500)
- fade(QuickSettings.rootElementKey)
+ translate(QuickSettings.rootElementKey, Edge.Top, true)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
index 1d57c1a..45df2b1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
@@ -1,11 +1,12 @@
package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.systemui.scene.ui.composable.Shade
fun TransitionBuilder.goneToShadeTransition() {
spec = tween(durationMillis = 500)
- fade(Shade.rootElementKey)
+ translate(Shade.rootElementKey, Edge.Top, true)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
index 9a8a3e2..e63bc4e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
@@ -1,11 +1,12 @@
package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.systemui.scene.ui.composable.QuickSettings
fun TransitionBuilder.lockscreenToQuickSettingsTransition() {
spec = tween(durationMillis = 500)
- fade(QuickSettings.rootElementKey)
+ translate(QuickSettings.rootElementKey, Edge.Top, true)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 6c7964b..21a10b1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -10,6 +10,5 @@
spec = tween(durationMillis = 500)
translate(Notifications.Elements.Notifications, Edge.Bottom)
- fade(Notifications.Elements.Notifications)
timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index d65edae..0fa4ebd 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -409,6 +409,18 @@
scope.launch(bgDispatcher) { mutateSetting { it.copy(seedColor = value) } }
}
+ // Returns currentClockId if clock is connected, otherwise DEFAULT_CLOCK_ID. Since this
+ // is dependent on which clocks are connected, it may change when a clock is installed or
+ // removed from the device (unlike currentClockId).
+ // TODO: Merge w/ CurrentClockId when we convert to a flow. We shouldn't need both behaviors.
+ val activeClockId: String
+ get() {
+ if (!availableClocks.containsKey(currentClockId)) {
+ return DEFAULT_CLOCK_ID
+ }
+ return currentClockId
+ }
+
init {
// Register default clock designs
for (clock in defaultClockProvider.getClocks()) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index e539c95..b28920c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -62,9 +62,10 @@
private val burmeseLineSpacing =
resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese)
private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale)
+ protected var onSecondaryDisplay: Boolean = false
override val events: DefaultClockEvents
- override val config = ClockConfig()
+ override val config = ClockConfig(DEFAULT_CLOCK_ID)
init {
val parent = FrameLayout(ctx)
@@ -142,6 +143,11 @@
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSizePx)
recomputePadding(targetRegion)
}
+
+ override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {
+ this@DefaultClockController.onSecondaryDisplay = onSecondaryDisplay
+ recomputePadding(null)
+ }
}
open fun recomputePadding(targetRegion: Rect?) {}
@@ -182,13 +188,19 @@
override fun recomputePadding(targetRegion: Rect?) {
// We center the view within the targetRegion instead of within the parent
// view by computing the difference and adding that to the padding.
- val parent = view.parent
- val yDiff =
- if (targetRegion != null && parent is View && parent.isLaidOut())
- targetRegion.centerY() - parent.height / 2f
- else 0f
val lp = view.getLayoutParams() as FrameLayout.LayoutParams
- lp.topMargin = (-0.5f * view.bottom + yDiff).toInt()
+ lp.topMargin =
+ if (onSecondaryDisplay) {
+ // On the secondary display we don't want any additional top/bottom margin.
+ 0
+ } else {
+ val parent = view.parent
+ val yDiff =
+ if (targetRegion != null && parent is View && parent.isLaidOut())
+ targetRegion.centerY() - parent.height / 2f
+ else 0f
+ (-0.5f * view.bottom + yDiff).toInt()
+ }
view.setLayoutParams(lp)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index d962732..e2f4793 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -177,6 +177,9 @@
* targetRegion is relative to the parent view.
*/
fun onTargetRegionChanged(targetRegion: Rect?)
+
+ /** Called to notify the clock about its display. */
+ fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean)
}
/** Tick rates for clocks */
@@ -196,6 +199,8 @@
/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
+ val id: String,
+
/** Transition to AOD should move smartspace like large clock instead of small clock */
val useAlternateSmartspaceAODTransition: Boolean = false,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index cf7d2c5..3d9645a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -58,9 +58,26 @@
void userActivity();
void getState();
- boolean areCaptionsEnabled();
- void setCaptionsEnabled(boolean isEnabled);
+ /**
+ * Get Captions enabled state
+ *
+ * @param checkForSwitchState set true when we'd like to switch captions enabled state after
+ * getting the latest captions state.
+ */
+ void getCaptionsEnabledState(boolean checkForSwitchState);
+ /**
+ * Set Captions enabled state
+ *
+ * @param enabled the captions enabled state we'd like to update.
+ */
+ void setCaptionsEnabledState(boolean enabled);
+
+ /**
+ * Get Captions component state
+ *
+ * @param fromTooltip if it's triggered from tooltip.
+ */
void getCaptionsComponentState(boolean fromTooltip);
@ProvidesInterface(version = StreamState.VERSION)
@@ -192,7 +209,22 @@
void onScreenOff();
void onShowSafetyWarning(int flags);
void onAccessibilityModeChanged(Boolean showA11yStream);
+
+ /**
+ * Callback function for captions component state changed event
+ *
+ * @param isComponentEnabled the lateset captions component state.
+ * @param fromTooltip if it's triggered from tooltip.
+ */
void onCaptionComponentStateChanged(Boolean isComponentEnabled, Boolean fromTooltip);
+
+ /**
+ * Callback function for captions enabled state changed event
+ *
+ * @param isEnabled the lateset captions enabled state.
+ * @param checkBeforeSwitch intend to switch captions enabled state after the callback.
+ */
+ void onCaptionEnabledStateChanged(Boolean isEnabled, Boolean checkBeforeSwitch);
// requires version 2
void onShowCsdWarning(@AudioManager.CsdWarning int csdWarning, int durationMs);
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml
new file mode 100644
index 0000000..593f507f
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/presentation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.keyguard.KeyguardStatusView
+ android:id="@+id/clock"
+ android:layout_width="410dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/keyguard_clock_container"
+ layout="@layout/keyguard_clock_switch"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </com.android.keyguard.KeyguardStatusView>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
new file mode 100644
index 0000000..952f056
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/carrier_combo"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.util.AutoMarqueeTextView
+ android:id="@+id/mobile_carrier_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/qs_carrier_margin_width"
+ android:visibility="gone"
+ android:textDirection="locale"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:singleLine="true"
+ android:maxEms="7"/>
+
+ <include layout="@layout/status_bar_mobile_signal_group_new" />
+
+</com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView>
+
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index fc92e01..2eb1bb5 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN word vereis ná vassluit"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Wagwoord word vereis ná vassluit"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Patroon word vereis ná vassluit"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Die opdatering sal installeer wanneer die toestel nie gebruik word nie"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Meer sekuriteit vereis. PIN ruk lank nie gebruik nie."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Meer sekuriteit vereis. Wagwoord ruk lank nie gebruik nie."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Meer sekuriteit vereis. Patroon ruk lank nie gebruik nie."</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 88670cd..5fd946b 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ከመቆለፊያ በኋላ ፒን ያስፈልጋል"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ከመቆለፊያ በኋላ የይለፍ ቃል ያስፈልጋል"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ከመቆለፊያ በኋላ ስርዓተ ጥለት ያስፈልጋል"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"መሣሪያው ጥቅም ላይ በማይውልበት ጊዜ ዝማኔ ይጫናል"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። ፒን ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። የይለፍ ቃል ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። ስርዓተ ጥለት ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index b66f6fd..b6479f4 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"يجب إدخال رقم التعريف الشخصي بعد إلغاء التأمين."</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"يجب إدخال كلمة المرور بعد إلغاء التأمين."</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"يجب رسم النقش بعد إلغاء التأمين."</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"سيتم تثبيت التحديث عندما لا يكون الجهاز قيد الاستخدام."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"يجب تعزيز الأمان. لم يُستخدَم رقم PIN لبعض الوقت."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"يجب تعزيز الأمان. لم تستخدَم كلمة المرور لبعض الوقت."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"يجب تعزيز الأمان. لم يُستخدَم النقش لبعض الوقت."</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 6796756..a41a704 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"লকডাউনৰ পাছত পিন দিয়াৰ আৱশ্যক"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"লকডাউনৰ পাছত পাছৱৰ্ড দিয়াৰ আৱশ্যক"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"লকডাউনৰ পাছত আৰ্হি দিয়াৰ আৱশ্যক"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ডিভাইচটো ব্যৱহাৰ হৈ নাথাকোঁতে আপডে’ট ইনষ্টল হ’ব"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি আৰ্হি ব্যৱহাৰ কৰা হোৱা নাই।"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি পাছৱৰ্ড ব্যৱহাৰ কৰা হোৱা নাই।"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি আৰ্হি ব্যৱহাৰ কৰা হোৱা নাই।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index d8cf6c0..f66fb3c 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Kilidləmədən sonra PIN tələb edilir"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kilidləmədən sonra parol tələb edilir"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kilidləmədən sonra model tələb edilir"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Cihaz istifadə edilmədikdə güncəllənmə quraşdırılacaq"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Qoruma lazımdır. PIN bir müddət işlənməyib."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Qoruma lazımdır. Parol bir müddət işlənməyib."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Qoruma lazımdır. Model bir müddət işlənməyib."</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 72067e7..b0a6471 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je obavezan posle zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lozinka je obavezna posle zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Šablon je obavezan posle zaključavanja"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ažuriranje će se instalirati kada se uređaj ne koristi"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna zaštita. PIN dugo nije korišćen."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna zaštita. Lozinka dugo nije korišćena."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna zaštita. Šablon dugo nije korišćen."</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 12c693f..11cc77d 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Пасля блакіроўкі неабходна ўвесці PIN-код"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Пасля блакіроўкі неабходна ўвесці пароль"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Пасля блакіроўкі неабходна ўвесці ўзор разблакіроўкі"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Абнаўленне будзе ўсталявана, калі прылада не выкарыстоўваецца"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся PIN-код."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся пароль."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся ўзор разблакіроўкі."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 6726d42..c554a27 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"След заключването се изисква ПИН код"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"След заключването се изисква парола"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"След заключването се изисква фигура"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Актуализацията ще се инсталира, когато устройството не се използва"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Изисква се допъл. защита. ПИН кодът не е ползван скоро."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Изисква се допъл. защита. Паролата не е ползвана скоро."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Изисква се допъл. защита. Фигурата не е ползвана скоро."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 457f85d..69f533c 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"লকডাউন হওয়ার পরে পিন দিতে হবে"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"লকডাউন হওয়ার পরে পাসওয়ার্ড দিতে হবে"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"লকডাউন হওয়ার পরে প্যাটার্ন দিতে হবে"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ডিভাইস ব্যবহার না করাকালীন আপডেট ইনস্টল করা হবে"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"অতিরিক্ত সুরক্ষা দরকার। পিন কিছুক্ষণ ব্যবহার করা হয়নি।"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"অতিরিক্ত সুরক্ষা দরকার। পাসওয়ার্ড কিছুক্ষণ ব্যবহার করা হয়নি।"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"অতিরিক্ত সুরক্ষা দরকার। প্যাটার্ন কিছুক্ষণ ব্যবহার করা হয়নি।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 6dc147f..4c519c8 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je potreban nakon zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lozinka je potrebna nakon zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Uzorak je potreban nakon zaključavanja"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ažuriranje će se instalirati dok se uređaj ne koristi"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna zaštita. PIN dugo nije unošen."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna zaštita. Lozinka dugo nije unošena."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna zaštita. Uzorak dugo nije unošen."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 8b901c0..3bd6508 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Cal el PIN després del bloqueig de seguretat"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Cal la contrasenya després del bloqueig de seguretat"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Cal el patró després del bloqueig de seguretat"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"L\'actualització s\'instal·larà quan el dispositiu no estigui en ús"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Cal més seguretat. Fa temps que no utilitzes el PIN."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Cal més seguretat. Contrasenya no utilitzada fa temps."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Cal més seguretat. Fa temps que no utilitzes el patró."</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index b4c0343..e075d85 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po uzamčení je třeba zadat PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po uzamčení je třeba zadat heslo"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po uzamčení je třeba zadat gesto"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Aktualizace se nainstaluje, až zařízení nebudete používat"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Je potřeba další krok. PIN dlouho nepoužit."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Je potřeba další krok. Heslo dlouho nepoužito."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Je potřeba další krok. Gesto dlouho nepoužito."</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 3840785..027166f 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pinkode er påkrævet efter brug af låsning"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Adgangskode er påkrævet efter brug af låsning"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mønster er påkrævet efter brug af låsning"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Opdateringen installeres, når enheden ikke er i brug"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mere sikkerhed er påkrævet. Pinkoden er ikke blevet brugt i et stykke tid."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mere sikkerhed er påkrævet. Adgangskoden er ikke blevet brugt i et stykke tid."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Mere sikkerhed er påkrævet. Mønsteret er ikke blevet brugt i et stykke tid."</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 5d069ff..117f7a9 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Nach einer Sperre muss die PIN eingegeben werden"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Nach einer Sperre muss das Passwort eingegeben werden"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Nach einer Sperre muss das Muster gezeichnet werden"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update wird installiert, wenn das Gerät nicht verwendet wird"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Zusätzliche Sicherheitsmaßnahme erforderlich. Die PIN wurde länger nicht genutzt."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Zusätzliche Sicherheitsmaßnahme erforderlich. Passwort wurde länger nicht genutzt."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Zusätzliche Sicherheitsmaßnahme erforderlich. Muster wurde länger nicht genutzt."</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index f02be89..cd7637c 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Απαιτείται PIN μετά από κλείδωμα"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Απαιτείται κωδικός πρόσβασης μετά από κλείδωμα"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Απαιτείται μοτίβο μετά από κλείδωμα"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Η ενημέρωση θα εγκατασταθεί όταν δεν χρησιμοποιείται η συσκευή"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Απαιτ. πρόσθ. ασφάλ. Το PIN έχει καιρό να χρησιμοπ."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Απαιτ. πρόσθ. ασφάλ. Ο κωδ. πρ. έχει καιρό να χρησ."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Απαιτ. πρόσθ. ασφάλ. Το μοτίβο έχει καιρό να χρησιμ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index ab7208b..0ace8a7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update will be installed when the device is not in use"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index ab7208b..0ace8a7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update will be installed when the device is not in use"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index ab7208b..0ace8a7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update will be installed when the device is not in use"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 2aa9c04..debbeb1 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Se requiere el PIN después del bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Se requiere la contraseña después del bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Se requiere el patrón después del bloqueo"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Se instalará la actualización cuando el dispositivo esté en desuso"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Reforzar seguridad. PIN sin uso mucho tiempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Reforzar seguridad. Contraseña sin uso mucho tiempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Reforzar seguridad. Patrón sin uso mucho tiempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 78ecc85..0ea98a8 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Se necesita el PIN después del bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Se necesita la contraseña después del bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Se necesita el patrón después del bloqueo"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"La actualización se instalará cuando el dispositivo no esté en uso"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Se debe reforzar la seguridad. PIN no usado en mucho tiempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Se debe reforzar la seguridad. Contraseña no usada en mucho tiempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Se debe reforzar la seguridad. Patrón no usado en mucho tiempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 26ead1f..722a022 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pärast lukustamist on PIN-kood nõutav"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pärast lukustamist on parool nõutav"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pärast lukustamist on muster nõutav"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Värskendus installitakse, kui seadet ei kasutata"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Turvalisuse suurendamine on nõutav. PIN-koodi ei ole mõnda aega kasutatud."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Turvalisuse suurendamine on nõutav. Parooli ei ole mõnda aega kasutatud."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Turvalisuse suurendamine on nõutav. Mustrit ei ole mõnda aega kasutatud."</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 52d2336..d329369 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PINa behar da blokeoa desgaitu ostean"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pasahitza behar da blokeoa desgaitu ostean"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Eredua behar da blokeoa desgaitu ostean"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Gailua erabiltzen ari ez zarenean instalatuko da eguneratzea"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurtasuna areagotu behar da. PINa ez da erabili aldi batez."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurtasuna areagotu behar da. Pasahitza ez da erabili aldi batez."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurtasuna areagotu behar da. Eredua ez da erabili aldi batez."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 1e7978e..4815815 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"بعداز قفل همه باید از پین استفاده کرد"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"بعداز قفل همه باید از گذرواژه استفاده کرد"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"بعداز قفل همه باید از الگو استفاده کرد"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"بهروزرسانی وقتی دستگاه درحال استفاده نیست نصب خواهد شد"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"امنیت بیشتر لازم است. مدتی از پین استفاده نشده است."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"امنیت بیشتر لازم است. گذرواژه مدتی استفاده نشده است."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"امنیت بیشتر لازم است. مدتی از الگو استفاده نشده است."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 2ec0c99..02d41d8 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-koodi tarvitaan lukitustilan jälkeen"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Salasana tarvitaan lukitustilan jälkeen"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kuvio tarvitaan lukitustilan jälkeen"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Päivitys asennetaan, kun laite ei ole käytössä"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Lisäsuojausta tarvitaan. PIN-koodia ei ole käytetty."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Lisäsuojausta tarvitaan. Salasanaa ei ole käytetty."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Lisäsuojausta tarvitaan. Kuviota ei ole käytetty."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index b0bfa33..fa1a191 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Le NIP est requis après le verrouillage"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Le mot de passe est requis après le verrouillage"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Le schéma est requis après le verrouillage"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"La mise à jour sera installée lorsque l\'appareil n\'est pas utilisé"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Plus de sécurité requise. NIP non utilisé pour un temps."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Plus de sécurité requise. MDP non utilisé pour un temps."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Plus de sécurité requise. Schéma non utilisé pour un temps."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 5161832..d687a1d 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Code requis après un blocage"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Mot de passe requis après un blocage"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Schéma requis après un blocage"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"La mise à jour aura lieu lorsque votre appareil n\'est pas utilisé"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Code inutilisé depuis un moment. Renforcez la sécurité."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mot de passe inutilisé depuis un moment. Renforcez la sécurité."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Schéma inutilisé depuis un moment. Renforcez la sécurité."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index e33a899..3faa7ca 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Requírese o PIN tras o bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Requírese o contrasinal tras o bloqueo"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Requírese o padrón tras o bloqueo"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"A actualización instalarase cando o dispositivo non se estea usando"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Requírese seguranza adicional. O PIN non se usou desde hai tempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Requírese seguranza adicional. O contrasinal non se usou desde hai tempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Requírese seguranza adicional. O padrón non se usou desde hai tempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 1d806ca..99c9883 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"પિન પછી પાસવર્ડ આવશ્યક છે"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"લૉકડાઉન પછી પાસવર્ડ આવશ્યક છે"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"પૅટર્ન પછી પાસવર્ડ આવશ્યક છે"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"જ્યારે ડિવાઇસ ઉપયોગમાં ન હોય ત્યારે અપડેટ ઇન્સ્ટૉલ કરવામાં આવશે"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પિનનો ઉપયોગ થયો નથી."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પાસવર્ડનો ઉપયોગ થયો નથી."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પૅટર્નનો ઉપયોગ થયો નથી."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 808950e..9d32f04 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लॉकडाउन के बाद, पिन डालना ज़रूरी है"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लॉकडाउन के बाद, पासवर्ड डालना ज़रूरी है"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लॉकडाउन के बाद, पैटर्न ड्रॉ करना ज़रूरी है"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"अपडेट तब इंस्टॉल किया जाएगा, जब डिवाइस का इस्तेमाल न किया जा रहा हो"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पिन नहीं डाला गया."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पासवर्ड नहीं डाला गया."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पैटर्न ड्रॉ नहीं किया गया."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 970ae5c..b4224bf 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je obavezan nakon zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Zaporka je obavezna nakon zaključavanja"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Uzorak je obavezan nakon zaključavanja"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ažuriranje će se instalirati kad uređaj nije u upotrebi"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna sigurnost. PIN nije upotrijebljen duže vrijeme."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna sigurnost. Zaporka nije upotrijebljena duže vrijeme."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna sigurnost. Uzorak nije upotrijebljen duže vrijeme."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index bc0a98d..bc712c7 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-kód megadása szükséges a zárolás után"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Jelszó megadása szükséges a zárolás után"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Minta megadása szükséges a zárolás után"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"A frissítést telepíti a rendszer, amikor nincs használatban az eszköz"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Fokozott biztonság szükséges. Régóta nem használta a PIN-t."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Fokozott biztonság szükséges. Régóta nem használta jelszavát."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Fokozott biztonság szükséges. Régóta nem használta a mintát."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 230c6ba..4d7bbbe 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Արգելափակումից հետո հարկավոր է մուտքագրել PIN կոդը"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Արգելափակումից հետո հարկավոր է մուտքագրել գաղտնաբառը"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Արգելափակումից հետո հարկավոր է գծել նախշը"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Թարմացումը կտեղադրվի, երբ սարքն օգտագործվելիս չլինի"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"PIN կոդը որոշ ժամանակ չի օգտագործվել։"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Գաղտնաբառը որոշ ժամանակ չի օգտագործվել։"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Նախշը որոշ ժամանակ չի օգտագործվել։"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index cf01634..aa766e9 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN diperlukan setelah kunci total"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Sandi diperlukan setelah kunci total"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pola diperlukan setelah kunci total"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update akan diinstal saat perangkat sedang tidak digunakan"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Perlu keamanan tambahan. PIN tidak digunakan selama beberapa waktu."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Perlu keamanan tambahan. Sandi tidak digunakan selama beberapa waktu."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Perlu keamanan tambahan. Pola tidak digunakan selama beberapa waktu."</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index ca36400..99f1779 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-númers er krafist eftir læsingu"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Aðgangsorðs er krafist eftir læsingu"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mynsturs er krafist eftir læsingu"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Uppfærslan verður sett upp þegar tækið er ekki í notkun"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Viðbótaröryggis krafist. PIN-númer var ekki notað um hríð."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Viðbótaröryggis krafist. Aðgangsorð var ekki notað um hríð."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Viðbótaröryggis krafist. Mynstur var ekki notað um hríð."</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index e46ae37..e5079c7 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN richiesto dopo il blocco"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password richiesta dopo il blocco"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Sequenza richiesta dopo il blocco"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"L\'aggiornamento verrà installato quando il dispositivo non sarà in uso"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Occorre maggiore sicurezza. PIN non usato per un po\' di tempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Occorre maggiore sicurezza. Password non usata per un po\' di tempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Occorre maggiore sicurezza. Sequenza non usata per un po\' di tempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 667bf9b..bc66355 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"נדרש קוד אימות לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"נדרשת סיסמה לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"נדרש קו ביטול נעילה לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"העדכון יותקן כשהמכשיר לא יהיה בשימוש"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"נדרשת אבטחה מוגברת. לא השתמשת בקוד אימות זמן מה."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"נדרשת אבטחה מוגברת. לא השתמשת בסיסמה זמן מה."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"נדרשת אבטחה מוגברת. לא השתמשת בקו ביטול נעילה זמן מה."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 5230984..1d59a63 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ロックダウン後は PIN の入力が必要になります"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ロックダウン後はパスワードの入力が必要になります"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ロックダウン後はパターンの入力が必要になります"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"アップデートは、デバイスを使用していないときにインストールされます"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"セキュリティ強化が必要: PIN がしばらく未使用です。"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"セキュリティ強化が必要: パスワードがしばらく未使用です。"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"セキュリティ強化が必要: パターンがしばらく未使用です。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 04a7b0d..5bd6b2e 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"დაბლოკვის შემდეგ საჭიროა PIN-კოდი"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"დაბლოკვის შემდეგ საჭიროა პაროლი"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"დაბლოკვის შემდეგ საჭიროა ნიმუში"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"განახლება დაინსტალირდება, როცა მოწყობილობა არ გამოიყენება"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"საჭიროა დამ. უსაფრთ. PIN-კოდი ერთხანს არ გამოიყენ."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"საჭ. დამ. უსაფრთ. პაროლი ერთხანს არ გამოიყენება."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"საჭიროა დამ. უსაფრთ. ნიმუში ერთხანს არ გამოიყენება."</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index deab7b8..83d270d 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Құлыпталғаннан кейін PIN кодын енгізу қажет."</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Құлыпталғаннан кейін құпия сөз енгізу қажет."</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Құлыпталғаннан кейін өрнек енгізу қажет."</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Құрылғы қолданылмағанда жаңартылады."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Қауіпсіздікті күшейту қажет. PIN коды біраз уақыт қолданылмаған."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Қауіпсіздікті күшейту қажет. Құпия сөз біраз уақыт қолданылмаған."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Қауіпсіздікті күшейту қажет. Өрнек біраз уақыт қолданылмаған."</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 1325151..5306cb1 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ត្រូវការកូដ PIN បន្ទាប់ពីការចាក់សោ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ត្រូវការពាក្យសម្ងាត់បន្ទាប់ពីការចាក់សោ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ត្រូវការលំនាំបន្ទាប់ពីការចាក់សោ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"កំណែថ្មីនឹងត្រូវបានដំឡើង នៅពេលឧបករណ៍មិនជាប់ប្រើ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើកូដ PIN មួយរយៈ។"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើពាក្យសម្ងាត់មួយរយៈ។"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើលំនាំមួយរយៈ។"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 749ebb6..d609a23 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ಲಾಕ್ಡೌನ್ ಮಾಡಿದ ನಂತರ ಪಿನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ಲಾಕ್ಡೌನ್ನ ನಂತರ ಪಾಸ್ವರ್ಡ್ನ ಅಗತ್ಯವಿದೆ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ಲಾಕ್ಡೌನ್ ಮಾಡಿದ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ಸಾಧನವನ್ನು ಬಳಕೆ ಮಾಡದ ಸಮಯದಲ್ಲಿ ಅಪ್ಡೇಟ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪಿನ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index ae75286..532253e 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"기기가 잠겨 PIN을 입력해야 합니다."</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"기기가 잠겨 비밀번호를 입력해야 합니다."</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"기기가 잠겨 패턴을 입력해야 합니다."</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"기기를 사용하지 않을 때 업데이트가 설치됩니다."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"보안을 강화해야 합니다. 한동안 PIN이 사용되지 않았습니다."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"보안을 강화해야 합니다. 한동안 비밀번호가 사용되지 않았습니다."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"보안을 강화해야 합니다. 한동안 패턴이 사용되지 않았습니다."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 638fd98..9ad9d56 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Бекем кулпулангандан кийин PIN код талап кылынат"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Бекем кулпулангандан кийин сырсөз талап кылынат"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Бекем кулпулангандан кийн грфикалык ачкыч талп клынт"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Жаңыртуу түзмөк колдонулбай турганда орнотулат"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Кошмча кпсуздук тлап клнат. PIN код бир нче убкыт бою клднулгн эмeс."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Кошмча кпсуздук тлап клнат. Сырсз бир нче убкыт бою клднулгн эмeс."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Кошмча кпсуздук тлап клнат. Грфиклык ачкч бир нче убкыт бою клднулгн эмeс."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index efe5377..0059d7f 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ຕ້ອງໃສ່ PIN ຫຼັງຈາກທີ່ລັອກໄວ້"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ຕ້ອງໃສ່ລະຫັດຜ່ານຫຼັງຈາກທີ່ລັອກໄວ້"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ຕ້ອງແຕ້ມຮູບແບບຫຼັງຈາກທີ່ລັອກໄວ້"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ລະບົບຈະຕິດຕັ້ງການອັບເດດເມື່ອບໍ່ມີການນຳໃຊ້ອຸປະກອນ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ PIN ມາໄລຍະໜຶ່ງແລ້ວ."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ລະຫັດຜ່ານມາໄລຍະໜຶ່ງແລ້ວ."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ຮູບແບບມາໄລຍະໜຶ່ງແລ້ວ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 59f0aa3..01e2f88 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po užrakinimo reikalingas PIN kodas"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po užrakinimo reikalingas slaptažodis"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po užrakinimo reikalingas atrakinimo piešinys"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Naujinys bus įdiegtas, kai įrenginys nebus naudojamas"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Reikalinga papildoma sauga. PIN kodas nebuvo naudojamas kurį laiką."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Reikalinga papildoma sauga. Slaptažodis nebuvo naudojamas kurį laiką."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Reikalinga papildoma sauga. Atrakinimo piešinys nebuvo naudojamas kurį laiką."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index ee9e8c2..2133694 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pēc bloķēšanas ir jāievada PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pēc bloķēšanas ir jāievada parole"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pēc bloķēšanas ir jāzīmē kombinācija"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Atjauninājums tiks instalēts, kad ierīce netiks izmantota."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Jāveic papildu drošības darbība. PIN ilgu laiku nav lietots."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Jāveic papildu drošības darbība. Parole ilgu laiku nav lietota."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Jāveic papildu drošības darbība. Kombinācija ilgu laiku nav lietota."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index a869d60..2771c7f 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Потребен е PIN-код по заклучување"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Потребна е лозинка по заклучување"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Потребна е шема по заклучување"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ажурирањето ќе се инсталира кога нема да се користи уредот"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потребна е дополнителна безбедност. PIN-кодот не бил користен некое време."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потребна е дополнителна безбедност. Лозинката не била користена некое време."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потребна е дополнителна безбедност. Шемата не била користена некое време."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index e247cc7..02ee66f 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ലോക്ക്ഡൗണിന് ശേഷം പിൻ നൽകേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ലോക്ക്ഡൗണിന് ശേഷം പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ലോക്ക്ഡൗണിന് ശേഷം പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ഉപകരണം ഉപയോഗിക്കാതിരിക്കുമ്പോൾ അപ്ഡേറ്റ് ഇൻസ്റ്റാൾ ആകും"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"അധിക സുരക്ഷ വേണം. അൽപകാലം പിൻ ഉപയോഗിച്ചില്ല."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"അധിക സുരക്ഷ വേണം. അൽപകാലം പാസ്വേഡ് ഉപയോഗിച്ചില്ല."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"അധിക സുരക്ഷ വേണം. അൽപകാലം പാറ്റേൺ ഉപയോഗിച്ചില്ല."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 7b555fb64..2b9f81e 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Түгжсэний дараа ПИН шаардлагатай"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Түгжсэний дараа нууц үг шаардлагатай"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Түгжсэний дараа хээ шаардлагатай"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Төхөөрөмжийг ашиглаагүй үед шинэчлэлтийг суулгана"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Нэмэлт аюулгүй байдал шаардлагатай. ПИН-г хэсэг хугацаанд ашиглаагүй."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Нэмэлт аюулгүй байдал шаардлагатай. Нууц үгийг хэсэг хугацаанд ашиглаагүй."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Нэмэлт аюулгүй байдал шаардлагатай. Хээг хэсэг хугацаанд ашиглаагүй."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index ada2f11..7aa7bdd 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लॉकडाउननंतर पिन आवश्यक आहे"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लॉकडाउननंतर पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लॉकडाउननंतर पॅटर्न आवश्यक आहे"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"डिव्हाइस वापरात नसताना अपडेट इंस्टॉल केले जाईल"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पिन अनलॉक केला गेला नव्हता."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पासवर्ड अनलॉक केला गेला नव्हता."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पॅटर्न अनलॉक केला गेला नव्हता."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 60c4531..bdfa4a7 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN diperlukan selepas kunci semua"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kata laluan diperlukan selepas kunci semua"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Corak diperlukan selepas kunci semua"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Kemaskinian akan dipasang apabila peranti tidak digunakan"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Keselamatan tambahan diperlukan. PIN tidak digunakan."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Keselamatan tambahan diperlukan. Kata laluan tidak digunakan."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Keselamatan tambahan diperlukan. Corak tidak digunakan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 4092c9a..e85cf8a 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် ပင်နံပါတ်လိုအပ်သည်"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် စကားဝှက်လိုအပ်သည်"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် ပုံဖော်ခြင်းလိုအပ်သည်"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"စက်သုံးနေခြင်း မရှိချိန်တွင် အပ်ဒိတ် ထည့်သွင်းပါမည်"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ ပင်နံပါတ်မသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ စကားဝှက်မသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ ပုံဖော်ခြင်းမသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index deb1421..455d086 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-koden kreves etter låsing"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Passordet kreves etter låsing"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mønsteret kreves etter låsing"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Oppdateringen installeres når enheten ikke brukes"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Økt sikkerhet kreves. Har ikke brukt PIN-koden nylig"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Økt sikkerhet kreves. Har ikke brukt passordet nylig"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Økt sikkerhet kreves. Har ikke brukt mønsteret nylig"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 4cc238d..f0094a3 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लकडाउन गरेपछि PIN हाल्नु पर्ने हुन्छ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लकडाउन गरेपछि पासवर्ड हाल्नु पर्ने हुन्छ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लकडाउन गरेपछि प्याटर्न कोर्नु पर्ने हुन्छ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"डिभाइस नचलाइएका बेला अपडेट इन्स्टल हुने छ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि PIN प्रयोग गरिएको छैन।"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि पासवर्ड प्रयोग गरिएको छैन।"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि प्याटर्न प्रयोग गरिएको छैन।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 60578fa..a236639 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Na lockdown is de pincode vereist"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Na lockdown is het wachtwoord vereist"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Na lockdown is het patroon vereist"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Update wordt geïnstalleerd als het apparaat niet wordt gebruikt"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Extra beveiliging. Pincode is lang niet gebruikt."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Extra beveiliging. Wachtwoord is lang niet gebruikt."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Extra beveiliging. Patroon is lang niet gebruikt."</string>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 4baae48..b31c9c0 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ଲକଡାଉନ ହେବା ପରେ PIN ଆବଶ୍ୟକ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ଲକଡାଉନ ହେବା ପରେ ପାସୱାର୍ଡ ଆବଶ୍ୟକ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ଲକଡାଉନ ହେବା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ଡିଭାଇସ ବ୍ୟବହାର କରାଯାଉନଥିବା ବେଳେ ଅପଡେଟ ଇନଷ୍ଟଲ ହେବ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ PIN ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ ପାସୱାର୍ଡ ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ ପାଟର୍ନ ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 2306832..209b63f 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪਿੰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ਡੀਵਾਈਸ ਵਰਤੋਂ ਵਿੱਚ ਨਾ ਹੋਣ \'ਤੇ ਅੱਪਡੇਟ ਸਥਾਪਤ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪਿੰਨ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪਾਸਵਰਡ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪੈਟਰਨ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index f30d2cf..7ec988e 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po zablokowaniu wymagany jest kod PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po zablokowaniu wymagane jest hasło"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po zablokowaniu wymagany jest wzór"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Instalacja aktualizacji nastąpi, gdy urządzenie nie będzie w użyciu"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Wzmocnij ochronę. Od dawna nie używano kodu PIN."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Wzmocnij ochronę. Od dawna nie używano hasła."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Wzmocnij ochronę. Od dawna nie używano wzoru."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index e9b21ed..78a8091 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é obrigatório após o Bloqueio total"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A senha é obrigatória após o Bloqueio total"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é obrigatório após o Bloqueio total"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"A atualização será instalada quando o dispositivo não estiver em uso"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurança necessária. PIN não usado há um tempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurança necessária. Senha não usada há um tempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurança necessária. Padrão não usado há um tempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index b10f313..2dc7d27 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é necessário após o bloqueio"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A palavra-passe é necessária após o bloqueio"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é necessário após o bloqueio"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"A atualização é instalada quando o dispositivo não estiver a ser usado"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mais segurança necessária. PIN não usado há muito."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mais segurança necessária. Não usada há muito."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"+ segurança necessária. Padrão não usado há muito."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index e9b21ed..78a8091 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é obrigatório após o Bloqueio total"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A senha é obrigatória após o Bloqueio total"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é obrigatório após o Bloqueio total"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"A atualização será instalada quando o dispositivo não estiver em uso"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurança necessária. PIN não usado há um tempo."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurança necessária. Senha não usada há um tempo."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurança necessária. Padrão não usado há um tempo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 3799ce7..e5be788 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Codul PIN este solicitat după blocarea strictă"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Parola este solicitată după blocarea strictă"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Modelul este solicitat după blocarea strictă"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Actualizarea se va instala când dispozitivul nu este folosit"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mai multă securitate necesară. PIN-ul nu a fost folosit de ceva timp."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mai multă securitate necesară. Parola nu a fost folosită de ceva timp."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Mai multă securitate necesară. Modelul nu a fost folosit de ceva timp."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 184b28d..45149a5 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"После блокировки необходимо ввести PIN-код."</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"После блокировки необходимо ввести пароль."</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"После блокировки необходимо ввести графический ключ."</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Обновление будет установлено, когда устройство не используется."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"PIN-код давно не использовался. Усильте защиту."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Пароль давно не использовался. Усильте защиту."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Граф. ключ давно не использовался. Усильте защиту."</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index a484119..17ced75 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"අගුළු දැමීමෙන් පසු PIN අවශ්ය වේ"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"අගුළු දැමීමෙන් පසු මුරපදය අවශ්ය වේ"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"අගුළු දැමීමෙන් පසු රටාව අවශ්ය වේ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"උපාංගය භාවිතයේ නොමැති විට යාවත්කාලීනය ස්ථාපනය වනු ඇත"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"අමතර ආරක්ෂාවක් අවශ්යයි. PIN ටික කලකට භාවිතා කර නැත."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"අමතර ආරක්ෂාවක් අවශ්යයි. මුරපදය ටික කලකට භාවිතා කර නැත."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"අමතර ආරක්ෂාවක් අවශ්යයි. රටාව ටික කලකට භාවිතා කර නැත."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 4730273..ef08a6c 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po silnej zámke sa vyžaduje PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po silnej zámke sa vyžaduje heslo"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po silnej zámke sa vyžaduje vzor"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Aktualizácia sa nainštaluje, keď zariadenie nebudete používať"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Treba lepšie zabezp. Kód PIN nebol dlhšie použitý."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Treba lepšie zabezp. Heslo nebolo dlhšie použité."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Treba lepšie zabezp. Vzor nebol dlhšie použitý."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index bddb9ad..a42989c 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po zaklepu se zahteva vnos kode PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po zaklepu se zahteva vnos gesla"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po zaklepu se zahteva vnos vzorca"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Posodobitev bo nameščena, ko naprava ne bo v uporabi"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Zahtevana je dodatna varnost. Koda PIN nekaj časa ni bila uporabljena."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Zahtevana je dodatna varnost. Geslo nekaj časa ni bilo uporabljeno."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Zahtevana je dodatna varnost. Vzorec nekaj časa ni bil uporabljen."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1739119..84f7bb5 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pas bllokimit kërkohet kodi PIN"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pas bllokimit kërkohet fjalëkalimi"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pas bllokimit kërkohet motivi"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Përditësimi do të instalohet kur pajisja të mos përdoret"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Kërkohet një siguri më e lartë. Kodi PIN nuk është përdorur për njëfarë kohe."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Kërkohet një siguri më e lartë. Fjalëkalimi nuk është përdorur për njëfarë kohe."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Kërkohet një siguri më e lartë. Motivi nuk është përdorur për njëfarë kohe."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index b8c4b55..437018d 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN је обавезан после закључавања"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Лозинка је обавезна после закључавања"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Шаблон је обавезан после закључавања"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ажурирање ће се инсталирати када се уређај не користи"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потребна је додатна заштита. PIN дуго није коришћен."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потребна је додатна заштита. Лозинка дуго није коришћена."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потребна је додатна заштита. Шаблон дуго није коришћен."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index bec1771..b4b1996 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pinkod krävs efter låsning"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lösenord krävs efter låsning"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mönster krävs efter låsning"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Uppdateringen installeras när enheten inte används"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Ökad säkerhet krävs. Pinkoden har inte använts på länge."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Ökad säkerhet krävs. Lösenordet har inte använts på länge."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Ökad säkerhet krävs. Mönstret har inte använts på länge."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index c6a8ed5..8ca9046 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN inahitajika baada ya kufunga"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Nenosiri linahitajika baada ya kufunga"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mchoro unahitajika baada ya kufunga"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Sasisho litasakinishwa wakati hutumii kifaa"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Usalama wa ziada unahitajika. PIN haikutumika kwa muda."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Usalama wa ziada unahitajika. Nenosiri halikutumika kwa muda."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Usalama wa ziada unahitajika. Mchoro haukutumika kwa muda."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 147b36b..7671194 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"முழுப் பூட்டு காரணமாகப் பின் தேவை"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"முழுப் பூட்டு காரணமாகக் கடவுச்சொல் தேவை"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"முழுப் பூட்டு காரணமாகப் பேட்டர்ன் தேவை"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"சாதனம் உபயோகத்தில் இல்லாதபோது புதுப்பிப்பு நிறுவப்படும்"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"சேர்த்த பாதுகாப்பு தேவை. பின் உபயோகிக்கவில்லை."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"சேர்த்த பாதுகாப்பு தேவை. கடவுச்சொல் உபயோகிக்கவில்லை."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"சேர்த்த பாதுகாப்பு தேவை. பேட்டர்ன் உபயோகிக்கவில்லை."</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 317fb30..623b589 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"లాక్డౌన్ తర్వాత PIN అవసరం"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"లాక్డౌన్ తర్వాత పాస్వర్డ్ అవసరం"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"లాక్డౌన్ తర్వాత ఆకృతి అవసరం"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"పరికరం ఉపయోగంలో లేనప్పుడు అప్డేట్ ఇన్స్టాల్ చేయబడుతుంది"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"మరింత సెక్యూరిటీ యాడ్ చెయ్యాలి. PINని ఈమధ్య వాడలేదు."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"యాడెడ్ సెక్యూరిటీ కావాలి. పాస్వర్డ్ ఈ మధ్య వాడలేదు."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"మరింత సెక్యూరిటీ కావాలి. ఆకృతిని ఈ మధ్య వాడలేదు."</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 85a14fa..c244107 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ต้องป้อน PIN หลังจากการปิดล็อก"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ต้องป้อนรหัสผ่านหลังจากการปิดล็อก"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ต้องวาดรูปแบบหลังจากการปิดล็อก"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"ระบบจะติดตั้งการอัปเดตเมื่อไม่มีการใช้งานอุปกรณ์"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้ PIN มาระยะหนึ่ง"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้รหัสผ่านมาระยะหนึ่ง"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้รูปแบบมาระยะหนึ่ง"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 1e51e0b..cd8f810 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Kailangan ang PIN pagkatapos ng lockdown"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kailangan ang password pagkatapos ng lockdown"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kailangan ang pattern pagkatapos ng lockdown"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Ii-install ang update kapag hindi ginagamit ang device"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang PIN."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang password."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang pattern."</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 05a9c95..ddeba67 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Tam kilitlemenin ardından PIN gerekli"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Tam kilitlemenin ardından şifre gerekli"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Tam kilitlemenin ardından desen gerekli"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Güncelleme, cihazın kullanılmadığı bir sırada yüklenecek"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Daha fazla güvenlik gerekli. PIN bir süredir kullanılmamış."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Daha fazla güvenlik gerekli. Şifre bir süredir kullanılmamış."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Daha fazla güvenlik gerekli. Desen bir süredir kullanılmamış."</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 1c3c3ca..f06d17d 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Після блокування входу потрібно ввести PIN-код"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Після блокування входу потрібно ввести пароль"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Після блокування входу потрібно намалювати ключ"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Оновлення встановиться, коли пристрій не використовуватиметься"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потрібен додатковий захист. PIN-код довго не використовувався."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потрібен додатковий захист. Пароль довго не використовувався."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потрібен додатковий захист. Ключ довго не використовувався."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 7784766..8adbaca 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"لاک ڈاؤن کے بعد PIN کی ضرورت ہوتی ہے"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"لاک ڈاؤن کے بعد پاس ورڈ کی ضرورت ہوتی ہے"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"لاک ڈاؤن کے بعد پیٹرن کی ضرورت ہوتی ہے"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"آلہ استعمال میں نہ ہونے پر اپ ڈیٹ انسٹال ہو جائے گی"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"مزید سیکیورٹی چاہیے۔ PIN کچھ عرصے اسے استعمال نہیں ہوا ہے۔"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"مزید سیکیورٹی چاہیے۔ پاس ورڈ کچھ عرصے سے استعمال نہیں ہوا ہے۔"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"مزید سیکیورٹی چاہیے۔ پیٹرن کچھ عرصے سے استعمال نہیں ہوا ہے۔"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 28d18da..96dfa05 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Bloklangandan keyin PIN kodni kiritish kerak"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Bloklangandan keyin parolni kiritish kerak"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Bloklangandan keyin grafik kalitni chizish kerak"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Yangilanish qurilma ishlatilmaganda oʻrnatiladi"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Xavfsizlikni oshiring. PIN kod ancha vaqt ishlatilmadi."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Xavfsizlikni oshiring. Parol ancha vaqt ishlatilmadi."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Xavfsizlikni oshiring. Grafik kalit ancha vaqt chizilmadi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 726a9e7..94d4fe2 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Cần nhập mã PIN sau khi hết thời gian khoá"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Cần nhập mật khẩu sau khi hết thời gian khoá"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Cần vẽ hình mở khoá sau khi hết thời gian khoá"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Bản cập nhật sẽ được cài đặt khi bạn không sử dụng thiết bị"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Cần tăng cường bảo mật. Đã lâu chưa dùng mã PIN."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Cần tăng cường bảo mật. Đã lâu chưa dùng mật khẩu"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Cần tăng cường bảo mật. Đã lâu chưa dùng hình mở khoá."</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 0efe3bf..59261a3 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"一旦设备被锁定,必须输入 PIN 码才能解锁"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"一旦设备被锁定,必须输入密码才能解锁"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"一旦设备被锁定,必须绘制图案才能解锁"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"更新会在设备处于未使用状态时安装"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"需要锁定设备以提高安全性。已有一段时间未使用 PIN 码了。"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"需要锁定设备以提高安全性。已有一段时间未使用密码了。"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"需要锁定设备以提高安全性。已有一段时间未使用图案了。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 58c3034..dad6f31 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"需要輸入 PIN 才能解除鎖定"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"需要輸入密碼解才能解除鎖定"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"需要畫出解鎖圖案才能解除鎖定"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"系統會在裝置未使用時安裝更新"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"需要加強安全設定:已有一段時間沒有使用 PIN。"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"需要加強安全設定:已有一段時間沒有使用密碼。"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"需要加強安全設定:已有一段時間沒有使用解鎖圖案。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 35e7824..88b7e43 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"裝置鎖定後,必須輸入 PIN 碼才能解鎖"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"裝置鎖定後,必須輸入密碼才能解鎖"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"裝置鎖定後,必須畫出解鎖圖案才能解鎖"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"系統會在裝置處於未使用狀態時安裝更新"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"裝置已有一段時間未鎖定,請使用 PIN 碼鎖定裝置以策安全。"</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"裝置已有一段時間未鎖定,請使用密碼鎖定裝置以策安全。"</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"裝置已有一段時間未鎖定,請使用解鎖圖案鎖定裝置以策安全。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index e229c7e..c5e99ab 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -76,8 +76,7 @@
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Iphinikhodi iyadingeka ngemva kokukhiya"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Iphasiwedi iyadingeka ngemuva kokukhiya"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Iphethini iyadingeka ngemva kokukhiya"</string>
- <!-- no translation found for kg_prompt_unattended_update (4366635751738712452) -->
- <skip />
+ <string name="kg_prompt_unattended_update" msgid="4366635751738712452">"Isibuyekezo sizofakwa lapho idivayisi ingasetshenziswa"</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Ukuphepha okwengeziwe kuyadingeka. Iphinikhodi ayisetshenziswanga isikhathi eside."</string>
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Ukuphepha okwengeziwe kuyadingeka. Iphasiwedi ayisetshenziswanga isikhathi eside."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Ukuphepha okwengeziwe kuyadingeka. Iphethini ayisetshenziswanga isikhathi eside."</string>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
index 6895219..de308ddb 100644
--- a/packages/SystemUI/res-product/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -38,8 +38,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件账号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件账号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"手机先前因过热而关机"</string>
<string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"设备先前因过热而关机"</string>
<string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"平板电脑先前因过热而关机"</string>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index 4a9d41f..b83f15a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -14,6 +14,4 @@
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="3dp"
- android:insetRight="3dp"
android:drawable="@drawable/ic_speaker_mute" />
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 12f13e9..3a15ae4 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -127,6 +127,8 @@
android:gravity="center_vertical"
android:paddingStart="@dimen/shade_header_system_icons_padding_start"
android:paddingEnd="@dimen/shade_header_system_icons_padding_end"
+ android:paddingTop="@dimen/shade_header_system_icons_padding_top"
+ android:paddingBottom="@dimen/shade_header_system_icons_padding_bottom"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/privacy_container"
app:layout_constraintTop_toTopOf="@id/clock">
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
index 9af46c5..3796415 100644
--- a/packages/SystemUI/res/layout/screen_share_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -64,8 +64,7 @@
android:layout_height="wrap_content"
android:text="@string/screenrecord_permission_dialog_warning_entire_screen"
style="@style/TextAppearance.Dialog.Body.Message"
- android:gravity="start"
- android:lineHeight="@dimen/screenrecord_warning_line_height"/>
+ android:gravity="start"/>
<!-- Buttons -->
<LinearLayout
diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
index 78cd718..39ec09b 100644
--- a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
+++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
@@ -34,8 +34,8 @@
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
android:contentDescription="@string/screenshot_dismiss_work_profile">
<ImageView
- android:layout_width="16dp"
- android:layout_height="16dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
android:layout_gravity="center"
android:background="@drawable/circular_background"
android:backgroundTint="?androidprv:attr/materialColorSurfaceContainerHigh"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 2355341..fe80355 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g>-limiet"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Werkprogramme"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Onderbreek"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Aandbeligting"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan by sonsondergang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot sonsopkoms"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Maak vergrotinginstellings oop"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Maak vergrotinginstellings toe"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Sleep hoek om grootte te verander"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Laat diagonale rollees toe"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Verander grootte"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Maak <xliff:g id="APPNAME">%1$s</xliff:g> oop"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Om die Wallet-app as ’n kortpad by te voeg, moet jy seker maak dat die app geïnstalleer is"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Om die Wallet-app as ’n kortpad by te voeg, moet jy seker maak dat minstens een kaart bygevoeg is"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Om die QR-kodeskandeerder as ’n kortpad by te voeg, moet jy seker maak dat ’n kamera-app geïnstalleer is"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Om die Home-app as ’n kortpad by te voeg, moet jy seker maak dat die app geïnstalleer is"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Minstens een toestel beskikbaar is"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Kies ’n versteknotasapp om die notaneemkortpad te gebruik"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0fd3f11..63f1765 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ገደብ"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"የሥራ መተግበሪያዎች"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ባለበት ቆሟል"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"የምሽት ብርሃን"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ፀሐይ ስትጠልቅ ይበራል"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ፀሐይ እስክትወጣ ድረስ"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"የማጉያ ቅንብሮችን ክፈት"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"የማጉላት ቅንብሮችን ዝጋ"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"መጠን ለመቀየር ጠርዙን ይዘው ይጎትቱ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ሰያፍ ሽብለላን ፍቀድ"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"መጠን ቀይር"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ይክፈቱ"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"የWallet መተግበሪያን እንደ አቋራጭ ለማከል መተግበሪያው መጫኑን ያረጋግጡ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"የWallet መተግበሪያን እንደ አቋራጭ ለማከል ቢያንስ አንድ ካርድ መታከሉን ያረጋግጡ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"የQR ኮድ መቃኛውን እንደ አቋራጭ ለማከል የካሜራ መተግበሪያ መጫኑን ያረጋግጡ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"የHome መተግበሪያውን እንደ አቋራጭ ለማከል መተግበሪያው እንደተጫነ ያረጋግጡ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ቢያንስ አንድ መሣሪያ ይገኛል"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"የማስታወሻ አያያዝ አቋራጭን ለመጠቀም ነባሪ የማስታወሻ መተግበሪያ ይምረጡ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bb99e2c..8128fae 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"قيد <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"تطبيقات العمل"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"متوقّف مؤقَّتًا"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"الإضاءة الليلية"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"تفعيل عند غروب الشمس"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"حتى شروق الشمس"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"فتح إعدادات التكبير"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"إغلاق إعدادات التكبير"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"اسحب الزاوية لتغيير الحجم."</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"السماح بالتمرير القطري"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"تغيير الحجم"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"فتح \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"لإضافة تطبيق \"محفظة Google\" كاختصار، تأكَّد من أنّ التطبيق مثبَّت."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"لإضافة تطبيق \"محفظة Google\" كاختصار، تأكَّد من إضافة بطاقة واحدة على الأقل."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"لإضافة تطبيق الماسح الضوئي لرمز الاستجابة السريعة كاختصار، تأكَّد من أنّ تطبيق الكاميرا مثبَّت."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"لإضافة تطبيق Home كاختصار، تأكَّد من أنّ التطبيق مثبَّت."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• توفُّر جهاز واحد على الأقل"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"اختَر تطبيقًا تلقائيًا لتدوين الملاحظات لاستخدام اختصار تدوين الملاحظات."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d52301c..4915257 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সীমা"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সকীয়নি"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"কৰ্মস্থানৰ এপ্"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"পজ হৈ আছে"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ৰাতিৰ পোহৰ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূৰ্যাস্তত অন কৰক"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূৰ্যোদয়ৰ লৈকে"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বিবৰ্ধন কৰাৰ ছেটিং খোলক"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"বিবৰ্ধনৰ ছেটিং বন্ধ কৰক"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"আকাৰ সলনি কৰিবলৈ চুককেইটা টানি আনি এৰক"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"কোণীয়াকৈ স্ক্ৰ’ল কৰাৰ অনুমতি দিয়ক"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"আকাৰ সলনি কৰক"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খোলক"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet এপ্টোক এটা শ্বৰ্টকাট হিচাপে যোগ দিবলৈ, এপ্টো ইনষ্টল কৰি থোৱাটো নিশ্চিত কৰক"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet এপ্টোক এটা শ্বৰ্টকাট হিচাপে যোগ দিবলৈ, কমেও এখন কাৰ্ড যোগ দিয়াটো নিশ্চিত কৰক"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"কিউআৰ ক’ড স্কেনাৰক এটা শ্বৰ্টকাট হিচাপে যোগ দিবলৈ, কেমেৰা এপ্টো ইনষ্টল কৰি থোৱাটো নিশ্চিত কৰক"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home এপ্টোক এটা শ্বৰ্টকাট হিচাপে যোগ দিবলৈ, এপ্টো ইনষ্টল কৰি থোৱাটো নিশ্চিত কৰক"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• অতি কমেও এটা ডিভাইচ উপলব্ধ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"টোকা গ্ৰহণৰ শ্বৰ্টকাটটো ব্যৱহাৰ কৰিবলৈ এটা ডিফ’ল্ট টোকা গ্ৰহণৰ এপ্ বাছনি কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 85220a6..8d9fcbd 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"İş tətbiqləri"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Durdurulub"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Gecə işığı"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Qürubda aktiv ediləcək"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Şəfəq vaxtına qədər"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Böyütmə ayarlarını açın"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Böyütmə ayarlarını bağlayın"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Ölçüsünü dəyişmək üçün küncündən sürüşdürün"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diaqonal sürüşdürməyə icazə verin"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ölçüsünü dəyişin"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> tətbiqini açın"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pulqabı tətbiqini qısayol kimi əlavə etmək üçün tətbiq quraşdırılmalıdır"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pulqabı tətbiqini qısayol kimi əlavə etmək üçün kart əlavə edilməlidir"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR kod skanerini qısayol kimi əlavə etmək üçün kamera tətbiqi quraşdırılmalıdır"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home tətbiqini qısayol kimi əlavə etmək üçün tətbiq quraşdırılmalıdır"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ən azı bir cihaz əlçatandır"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Qeydgötürmə qısayolu üçün defolt qeyd tətbiqi seçin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3790300..e1bd89d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Poslovne aplikacije"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pauzirano"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noćno svetlo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Uključuje se po zalasku sunca"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do izlaska sunca"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori podešavanja uvećanja"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zatvori podešavanja uvećanja"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Zatvori režim izmene"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Prevucite ugao da biste promenili veličinu"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dozvoli dijagonalno skrolovanje"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Promeni veličinu"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Da biste dodali aplikaciju Novčanik kao prečicu, uverite se da je aplikacija instalirana"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Da biste dodali aplikaciju Novčanik kao prečicu, uverite se da je dodata bar jedna kartica"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Da biste dodali Skener QR koda kao prečicu, uverite se da je aplikacija za kameru instalirana"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Da biste dodali aplikaciju Home kao prečicu, uverite se da je aplikacija instalirana"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostupan je bar jedan uređaj"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Izaberite podrazumevanu aplikaciju za beleške da biste koristili prečicu za pravljenje beleški"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index def25b4..5d1b65c 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ліміт <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Працоўныя праграмы"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Профіль прыпынены"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Начная падсветка"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Уключаць увечары"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Да ўсходу сонца"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Адкрыць налады павелічэння"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Закрыць налады павелічэння"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Каб змяніць памер, перацягніце вугал"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дазволіць прагортванне па дыяганалі"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Змяніць памер"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Адкрыць праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Вы можаце дадаць ярлык праграмы \"Кашалёк\", толькі калі яна ўсталявана"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Вы можаце дадаць ярлык праграмы \"Кашалёк\", толькі калі дададзена хаця б адна картка"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Вы можаце дадаць ярлык сканера QR-кодаў, толькі калі ўсталявана праграма камеры"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Вы можаце дадаць ярлык праграмы Home, толькі калі яна ўсталявана"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Даступная хаця б адна прылада"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Выберыце стандартную праграму для нататак, якая будзе адкрывацца пры націсканні на ярлык"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 224ff1f..94ab2c9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ограничение от <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Служебни приложения"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"На пауза"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Нощно осветление"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ще се вкл. по залез"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До изгрев"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличаване на част от екрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отваряне на настройките за увеличението"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Затваряне на настройките за увеличение"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Изход от режима на редактиране"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Плъзнете ъгъла за преоразмеряване"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Разрешаване на диагонално превъртане"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Преоразмеряване"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отваряне на <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"За да добавите пряк път към приложението Wallet, уверете се, че то е инсталирано"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"За да добавите пряк път към приложението Wallet, уверете се, че е добавена поне една карта"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"За да добавите пряк път към скенера за QR кодове, уверете се, че е инсталирано приложение за камера"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"За да добавите пряк път към приложението Home, уверете се, че то е инсталирано"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Налице е поне едно устройство."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Изберете стандартно приложение за бележки, за да използвате прекия път за водене на бележки"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index aca0931..f80c301 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -295,6 +295,8 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"অফিসের অ্যাপ"</string>
+ <!-- no translation found for quick_settings_work_mode_paused_state (6681788236383735976) -->
+ <skip />
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"নাইট লাইট"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূর্যাস্তে চালু হবে"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূর্যোদয় পর্যন্ত"</string>
@@ -864,6 +866,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বড় করে দেখার সেটিংস খুলুন"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"\'বড় করে দেখা\' সেটিংস বন্ধ করুন"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ছোট বড় করার জন্য কোণ টেনে আনুন"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"কোনাকুনি স্ক্রল করার অনুমতি দেওয়া"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ছোট বড় করা"</string>
@@ -1133,7 +1137,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খুলুন"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet অ্যাপ, শর্টকাট হিসেবে যোগ করতে, অ্যাপ ইনস্টল করা আছে কিনা তা ভালভাবে দেখে নিন"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet অ্যাপ, শর্টকাট হিসেবে যোগ করতে, অন্তত একটি কার্ড যোগ করা হয়েছে কিনা তা ভালভাবে দেখে নিন"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR কোড স্ক্যানার, শর্টকাট হিসেবে যোগ করতে, ক্যামেরা অ্যাপ ইনস্টল করা আছে কিনা তা ভালভাবে দেখে নিন"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home অ্যাপ, শর্টকাট হিসেবে যোগ করতে, অ্যাপ ইনস্টল করা আছে কিনা তা ভালভাবে দেখে নিন"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• অন্তত একটি ডিভাইস উপলভ্য আছে"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"নোট নেওয়ার শর্টকাট ব্যবহার করতে, ডিফল্ট কোনও নোট অ্যাপ বেছে নিন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 1e4588d..364e847 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ograničenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Poslovne aplikacije"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pauzirano"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noćno svjetlo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Uključuje se u sumrak"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do svitanja"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori postavke uvećavanja"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zatvori postavke uvećavanja"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Izađi iz načina rada za uređivanje"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Prevucite ugao da promijenite veličinu"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dozvoli dijagonalno klizanje"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Promijeni veličinu"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvori aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Da dodate aplikaciju Novčanik kao prečicu, instalirajte aplikaciju"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Da dodate aplikaciju Novčanik kao prečicu, dodajte barem jednu karticu"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Da dodate skener QR koda kao prečicu, instalirajte aplikaciju kamere"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Da dodate aplikaciju Home kao prečicu, instalirajte aplikaciju"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostupan je najmanje jedan uređaj"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Odaberite zadanu aplikaciju za bilješke da koristite prečicu za zapisivanje bilješki"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a25cda6..557a7e6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Límit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplicacions de treball"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pausa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Llum nocturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Al vespre"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Fins a l\'alba"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Obre la configuració de l\'ampliació"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Tanca la configuració de l\'ampliació"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrossega el cantó per canviar la mida"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permet el desplaçament en diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Canvia la mida"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Obre <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Per afegir l\'aplicació Wallet com a drecera, assegura\'t que estigui instal·lada"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Per afegir l\'aplicació Wallet com a drecera, assegura\'t que s\'hagi afegit almenys una targeta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Per afegir l\'escàner de codis QR com a drecera, assegura\'t que hi hagi una aplicació de càmera instal·lada"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Per afegir l\'aplicació Home com a drecera, assegura\'t que estigui instal·lada"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Almenys un dispositiu està disponible."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecciona una aplicació de notes predeterminada per utilitzar la drecera de presa de notes"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 638c26a..0a83c86 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Pracovní aplikace"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pozastaveno"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noční režim"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Při soumraku"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do svítání"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otevřít nastavení zvětšení"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zavřít nastavení zvětšení"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Ukončit režim úprav"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Velikost změníte přetažením rohu"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Povolit diagonální posouvání"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Změnit velikost"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otevřít <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pokud chcete přidat aplikaci Peněženka jako zkratku, nainstalujte ji"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pokud chcete přidat aplikaci Peněženka jako zkratku, přidejte alespoň jednu kartu"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pokud chcete přidat skener QR kódů jako zkratku, ujistěte se, že je nainstalována aplikace k focení a natáčení"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pokud chcete přidat aplikaci Home jako zkratku, nainstalujte ji"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Je k dispozici alespoň jedno zařízení"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Vyberte výchozí aplikaci k psaní poznámek, ke které přidružíte zkratku pro poznámky"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 663aac4..9ebbebb 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Grænse: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Arbejdsapps"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Sat på pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nattelys"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Tænd ved solnedgang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Indtil solopgang"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Åbn indstillinger for forstørrelse"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Luk indstillinger for forstørrelse"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Træk i hjørnet for at justere størrelsen"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillad diagonal rulning"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Juster"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åbn <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Hvis du vil tilføje en genvej til Wallet-appen, skal du sørge for, at appen er installeret"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Hvis du vil tilføje en genvej til Wallet-appen, skal du sørge for, at du har tilføjet mindst ét kort"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Hvis du vil tilføje en genvej til QR-kodescanneren, skal du sørge for, at kameraappen er installeret"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Hvis du vil tilføje en genvej til Home-appen, skal du sørge for, at appen er installeret"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Mindst én enhed er tilgængelig"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Vælg en standardapp til noter for at bruge genvejen til notetagning"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ead5001..206e832 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> Datenlimit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Geschäftliche Apps"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausiert"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nachtlicht"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"An bei Sonnenuntergang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Bis Sonnenaufgang"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Vergrößerungseinstellungen öffnen"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Vergrößerungseinstellungen schließen"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Zum Anpassen der Größe Ecke ziehen"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonales Scrollen erlauben"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Größe ändern"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> öffnen"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Damit du die Wallet App als Verknüpfung hinzufügen kannst, muss die App installiert sein"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Damit du die Wallet App als Verknüpfung hinzufügen kannst, muss mindestens eine Karte hinzugefügt sein"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Damit du den QR-Code-Scanner als Verknüpfung hinzufügen kannst, muss eine Kamera-App installiert sein"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Damit du die Home App als Verknüpfung hinzufügen kannst, muss die App installiert sein"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Mindestens ein Gerät ist verfügbar"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Wähle eine Standard-App für Notizen aus, die du für die Verknüpfung verwenden möchtest"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 7a74831..c32cd17 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Όριο <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Εφαρμογές εργασιών"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Σε παύση"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Νυχτερινός φωτισμός"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Κατά τη δύση"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Μέχρι την ανατολή"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Μεγέθυνση μέρους της οθόνης"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Άνοιγμα ρυθμίσεων μεγιστοποίησης"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Κλείσιμο ρυθμίσεων μεγιστοποίησης"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Σύρετε τη γωνία για αλλαγή μεγέθους"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Να επιτρέπεται η διαγώνια κύλιση"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Αλλαγή μεγέθους"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Άνοιγμα <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Για να προσθέσετε ως συντόμευση την εφαρμογή Πορτοφόλι, βεβαιωθείτε ότι έχει εγκατασταθεί η εφαρμογή"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Για να προσθέσετε ως συντόμευση την εφαρμογή Πορτοφόλι, βεβαιωθείτε ότι έχει προστεθεί τουλάχιστον μία κάρτα"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Για να προσθέσετε ως συντόμευση τη Σάρωση κωδικών QR, βεβαιωθείτε ότι η εφαρμογή κάμερας είναι εγκατεστημένη"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Για να προσθέσετε την εφαρμογή Home ως συντόμευση, βεβαιωθείτε ότι η εφαρμογή είναι εγκατεστημένη"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Είναι διαθέσιμη τουλάχιστον μία συσκευή"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Επιλέξτε μια προεπιλεγμένη εφαρμογή σημειώσεων για να χρησιμοποιήσετε τη συντόμευση δημιουργίας σημειώσεων"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5d713bb..313f617 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -295,6 +295,8 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Work apps"</string>
+ <!-- no translation found for quick_settings_work_mode_paused_state (6681788236383735976) -->
+ <skip />
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Until sunrise"</string>
@@ -864,6 +866,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Close magnification settings"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Resize"</string>
@@ -1133,7 +1137,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure that the app is installed"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure that at least one card has been added"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure that a camera app is installed"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure that the app is installed"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the note-taking shortcut"</string>
@@ -1166,7 +1169,7 @@
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone & Camera"</string>
+ <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
<string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"Done"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 9d4a4fe..157570a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Work apps"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Paused"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Until sunrise"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Close magnification settings"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Exit edit mode"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Resize"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure the app is installed"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure at least one card has been added"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure a camera app is installed"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure the app is installed"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the notetaking shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5d713bb..313f617 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -295,6 +295,8 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Work apps"</string>
+ <!-- no translation found for quick_settings_work_mode_paused_state (6681788236383735976) -->
+ <skip />
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Until sunrise"</string>
@@ -864,6 +866,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Close magnification settings"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Resize"</string>
@@ -1133,7 +1137,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure that the app is installed"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure that at least one card has been added"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure that a camera app is installed"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure that the app is installed"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the note-taking shortcut"</string>
@@ -1166,7 +1169,7 @@
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone & Camera"</string>
+ <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
<string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"Done"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5d713bb..313f617 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -295,6 +295,8 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Work apps"</string>
+ <!-- no translation found for quick_settings_work_mode_paused_state (6681788236383735976) -->
+ <skip />
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Until sunrise"</string>
@@ -864,6 +866,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Close magnification settings"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Resize"</string>
@@ -1133,7 +1137,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure that the app is installed"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure that at least one card has been added"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure that a camera app is installed"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure that the app is installed"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the note-taking shortcut"</string>
@@ -1166,7 +1169,7 @@
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone & Camera"</string>
+ <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
<string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"Done"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 6a172f0..db7133c 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Work apps"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Paused"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Until sunrise"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Close magnification settings"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Exit edit mode"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Resize"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure the app is installed"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure at least one card has been added"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure a camera app is installed"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure the app is installed"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the notetaking shortcut"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4d0ed14..23d2edc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Apps de trabajo"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pausa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luz nocturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Al atardecer"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hasta el amanecer"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir la configuración de ampliación"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Cerrar configuración de ampliación"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Salir del modo de edición"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastra la esquina para cambiar el tamaño"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Desplazamiento en diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Cambiar tamaño"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para agregar la app de Billetera como acceso directo, asegúrate de haber instalado la app"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para agregar la app de Billetera como acceso directo, asegúrate de haber agregado al menos una tarjeta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para agregar el escáner de código QR como acceso directo, asegúrate de haber instalado la app de la cámara"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para agregar la app de Home como acceso directo, asegúrate de haber instalado la app"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Hay al menos un dispositivo disponible"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecciona una app de notas predeterminada para usar el acceso directo de toma de notas"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 953171a..1eb0abc 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplicaciones de trabajo"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pausa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luz nocturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Al atardecer"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hasta el amanecer"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir ajustes de ampliación"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Cerrar ajustes de ampliación"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastra la esquina para cambiar el tamaño"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir ir en diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Cambiar tamaño"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para añadir la aplicación Wallet como acceso directo, asegúrate de que está instalada"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para añadir la aplicación Wallet como acceso directo, asegúrate de haber añadido al menos una tarjeta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para añadir el escáner de códigos QR como acceso directo, asegúrate de que hay instalada una aplicación de cámara"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para añadir la aplicación Home como acceso directo, asegúrate de que está instalada"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Al menos un dispositivo debe estar disponible"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecciona una aplicación de notas predeterminada para usar el acceso directo de toma de notas"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 1e7bbf4..3881635 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limiit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Töörakendused"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Peatatud"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Öövalgus"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Sissel. päikeselooj."</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Kuni päikesetõusuni"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ava suurendamisseaded"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Sule suurendamisseaded"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Suuruse muutmiseks lohistage nurka"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Luba diagonaalne kerimine"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Muuda suurust"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ava <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Rahakotirakenduse otsetee lisamiseks veenduge, et rakendus oleks installitud"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Rahakotirakenduse otsetee lisamiseks veenduge, et vähemalt üks kaart oleks lisatud"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR-koodi skanneri otsetee lisamiseks veenduge, et kaamerarakendus oleks installitud"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Rakenduse Home otsetee lisamiseks veenduge, et rakendus oleks installitud"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Vähemalt üks seade on saadaval"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Valige märkmete tegemise vaikerakendus, et kasutada märkmete tegemise otseteed"</string>
@@ -1167,7 +1169,7 @@
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
<string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
<string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ja kaamera"</string>
- <string name="privacy_dialog_summary" msgid="2458769652125995409">"Rakenduse hiljutine kasutamine"</string>
+ <string name="privacy_dialog_summary" msgid="2458769652125995409">"Rakenduste hiljutine kasutamine"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kuva hiljutine juurdepääs"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"Valmis"</string>
<string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Laiendamine ja valikute kuvamine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 3ce64b2..0121abc 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Laneko aplikazioak"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausatuta"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Gaueko argia"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ilunabarrean"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Ilunabarrera arte"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ireki luparen ezarpenak"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Itxi luparen ezarpenak"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastatu izkina bat tamaina aldatzeko"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Eman diagonalki gora eta behera egiteko aukera erabiltzeko baimena"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Aldatu tamaina"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ireki <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Diru-zorroa aplikazioa lasterbide gisa gehitzeko, ziurtatu aplikazioa instalatuta dagoela."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Diru-zorroa aplikazioa lasterbide gisa gehitzeko, ziurtatu gutxienez txartel bat gehitu dela."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR kodeen eskanerra lasterbide gisa gehitzeko, ziurtatu kameraren aplikazioa instalatuta dagoela."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home aplikazioa lasterbide gisa gehitzeko, ziurtatu aplikazioa instalatuta dagoela."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Gutxienez gailu bat erabilgarri dago."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Oharrak idazteko lasterbidea erabiltzeko, hautatu oharretarako aplikazio lehenetsia."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 33bd9f4..a22f6da 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> محدودیت"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"برنامههای کاری"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"موقتاً متوقف شد"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"نور شب"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"غروب روشن میشود"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"تا طلوع"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"باز کردن تنظیمات درشتنمایی"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"بستن تنظیمات درشتنمایی"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"برای تغییر اندازه، گوشه را بکشید"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"اجازه دادن برای پیمایش قطری"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"تغییر اندازه"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"باز کردن <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"برای افزودن برنامه «کیف پول» بهعنوان میانبر، مطمئن شوید این برنامه نصب شده باشد"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"برای افزودن برنامه «کیف پول» بهعنوان میانبر، مطمئن شوید حداقل یک کارت اضافه شده باشد"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"برای افزودن «کدخوان پاسخسریع» بهعنوان میانبر، مطمئن شوید برنامه دوربین نصب شده باشد"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"برای افزودن برنامه Home بهعنوان میانبر، مطمئن شوید این برنامه نصب شده باشد"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• حداقل یک دستگاه دردسترس باشد"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"برای استفاده از میانبر یادداشتبرداری، برنامه یادداشت پیشفرضی را انتخاب کنید"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6da1262..d87f2f6 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"kiintiö <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Työsovellukset"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Keskeytetty"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Yövalo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Auringon laskiessa"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Auringonnousuun"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Avaa suurennusasetukset"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Sulje suurennusasetukset"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Muuta kokoa vetämällä kulmaa"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Salli diagonaalinen vierittäminen"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Muuta kokoa"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Avaa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Jos haluat lisätä Wallet-sovelluksen pikakuvakkeena, varmista, että se on asennettuna"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Jos haluat lisätä Wallet-sovelluksen pikakuvakkeena, varmista, että lisättynä on vähintään yksi kortti"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Jos haluat lisätä QR-koodiskannerin pikakuvakkeena, varmista, että kamerasovellus on asennettuna"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Jos haluat lisätä Home-sovelluksen pikakuvakkeena, varmista, että se on asennettuna"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ainakin yksi laite on käytettävissä"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Valitse muistiinpanojen tekemisen oletussovellus, jota käytetään pikakuvakkeen avulla"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2f8fcfb..1c6b508 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Applications professionnelles"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Éclairage nocturne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Activé la nuit"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Jusqu\'à l\'aube"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ouvrir les paramètres d\'agrandissement"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fermer les paramètres d\'agrandissement"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Faire glisser le coin pour redimensionner"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Autoriser défilement diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionner"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pour ajouter l\'application portefeuille sous forme de raccourci, assurez-vous que l\'application est installée"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pour ajouter l\'application Portefeuille sous forme de raccourci, assurez-vous qu\'au moins une carte a été ajoutée"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pour ajouter le numériseur de code QR sous forme de raccourci, assurez-vous qu\'une application d\'appareil photo est installée"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pour ajouter l\'application Home sous forme de raccourci, assurez-vous que l\'application est installée"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• qu\'au moins un appareil est utilisable;"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une application de prise de notes par défaut pour utiliser le raccourci de prise de notes"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3a77d37..420fd85 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> au maximum"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Applis pro"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Éclairage nocturne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Activé la nuit"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Jusqu\'à l\'aube"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ouvrir les paramètres d\'agrandissement"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fermer les paramètres d\'agrandissement"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Faire glisser le coin pour redimensionner"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Autoriser le défilement diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionner"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pour ajouter l\'appli Wallet comme raccourci, vérifiez que l\'appli est installée"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pour ajouter l\'appli Wallet comme raccourci, assurez-vous qu\'au moins une carte a été ajoutée"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pour ajouter le lecteur de code QR comme raccourci, assurez-vous qu\'une appli d\'appareil photo est installée"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pour ajouter l\'application Home comme raccourci, vérifiez que l\'appli est installée"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Au moins un appareil est disponible"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une appli de notes par défaut pour utiliser le raccourci de prise de notes"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 6390dc8..3389dd8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplicacións do traballo"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pausa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luz nocturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Activación ao solpor"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Ata o amencer"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplía parte da pantalla"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir configuración da ampliación"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Pechar configuración de ampliación"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastrar a esquina para cambiar o tamaño"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir desprazamento diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Cambiar tamaño"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para engadir a aplicación Wallet como atallo, asegúrate de que estea instalada"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para engadir a aplicación Wallet como atallo, asegúrate de que se incluíse polo menos unha tarxeta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para engadir o escáner de códigos QR como atallo, asegúrate de que a aplicación de cámara estea instalada"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para engadir a aplicación Google Home como atallo, asegúrate de que estea instalada"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ten que haber polo menos un dispositivo dispoñible"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecciona unha aplicación de notas predeterminada para usar o atallo de tomar notas"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 6a4fa7f..92ab77f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ઑફિસ માટેની ઍપ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"થોભાવ્યું"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"રાત્રિ પ્રકાશ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"સૂર્યાસ્ત વખતે"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"સૂર્યોદય સુધી"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"મોટા કરવાના સેટિંગ ખોલો"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"મોટા કરવાના સેટિંગ બંધ કરો"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"કદ બદલવા માટે ખૂણો ખેંચો"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ડાયગોનલ સ્ક્રોલિંગને મંજૂરી આપો"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"કદ બદલો"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ખોલો"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઓછામાં ઓછું એક કાર્ડ ઉમેરવામાં આવ્યું હોય"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR કોડ સ્કૅનરને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે કૅમેરા ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ઓછામાં ઓછું એક ડિવાઇસ ઉપલબ્ધ છે"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"નોંધ લેવાના શૉર્ટકટનો ઉપયોગ કરવા માટે, નોંધ માટેની ડિફૉલ્ટ ઍપ પસંદ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 091dd75..29f80aa 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -295,6 +295,8 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"वर्क ऐप्लिकेशन"</string>
+ <!-- no translation found for quick_settings_work_mode_paused_state (6681788236383735976) -->
+ <skip />
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"नाइट लाइट"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"शाम को चालू की जाएगी"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सुबह तक चालू रहेगी"</string>
@@ -864,6 +866,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ज़ूम करने की सुविधा वाली सेटिंग खोलें"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ज़ूम करने की सुविधा वाली सेटिंग को बंद करें"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"साइज़ बदलने के लिए, कोने को खींचें और छोड़ें"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"तिरछी दिशा में स्क्रोल करने की अनुमति दें"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"साइज़ बदलें"</string>
@@ -1133,7 +1137,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोलें"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि कम से कम एक कार्ड जोड़ा गया हो"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"क्यूआर कोड स्कैनर को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि कैमरा ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• कम से कम एक डिवाइस उपलब्ध है"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"नोट लेने से जुड़ा शॉर्टकट इस्तेमाल करने के लिए, नोट लेने का डिफ़ॉल्ट ऐप्लिकेशन चुनें"</string>
@@ -1168,7 +1171,7 @@
<string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
<string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string>
<string name="privacy_dialog_summary" msgid="2458769652125995409">"हाल ही में इस्तेमाल करने वाला ऐप्लिकेशन"</string>
- <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल ही का ऐक्सेस देखें"</string>
+ <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाले ऐप"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"हो गया"</string>
<string name="privacy_dialog_expand_action" msgid="9129262348628331377">"बड़ा करें और विकल्प दिखाएं"</string>
<string name="privacy_dialog_collapse_action" msgid="277419962019466347">"छोटा करें"</string>
@@ -1179,7 +1182,7 @@
<string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"फ़ोन कॉल पर इस्तेमाल किया जा रहा है"</string>
<string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"हाल ही में, फ़ोन कॉल में इस्तेमाल किया गया"</string>
<string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर इस्तेमाल किया जा रहा है"</string>
- <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"हाल ही में, <xliff:g id="APP_NAME">%1$s</xliff:g> ने इस्तेमाल किया"</string>
+ <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"हाल ही में <xliff:g id="APP_NAME">%1$s</xliff:g> पर इस्तेमाल किया गया"</string>
<string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) पर इस्तेमाल किया जा रहा है"</string>
<string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"हाल ही में, <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ने इस्तेमाल किया"</string>
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) पर इस्तेमाल किया जा रहा है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index baf74d2..e58bc76 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Poslovne aplikacije"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pauzirano"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noćno svjetlo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Uključuje se u suton"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do izlaska sunca"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori postavke povećavanja"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zatvori postavke povećavanja"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Zatvaranje načina uređivanja"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Povucite kut da biste promijenili veličinu"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dopusti dijagonalno pomicanje"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Promijeni veličinu"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Za dodavanje aplikacije Wallet kao prečaca provjerite je li instalirana"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Provjerite je li dodana barem jedna kartica kako biste dodali aplikaciju Wallet kao prečac"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Provjerite je li instalirana aplikacija kamere kako biste dodali čitač QR koda kao prečac"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Provjerite je li aplikacija Home instalirana kako biste je dodali kao prečac"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostupan je najmanje jedan uređaj"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Odaberite zadanu aplikaciju za bilješke da biste koristili prečac za pisanje bilježaka"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e225682..49ba82b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> korlát"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Munkahelyi alkalmazások"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Szüneteltetve"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Éjszakai fény"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Be: naplemente"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Napfelkeltéig"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Nagyítási beállítások megnyitása"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Nagyítási beállítások bezárása"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Az átméretezéshez húzza a kívánt sarkot"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Átlós görgetés engedélyezése"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Átméretezés"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> megnyitása"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ha szeretné felvenni Wallet alkalmazást gyorsparancsként, gondoskodjon az app telepítéséről"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ha szeretné felvenni Wallet alkalmazást gyorsparancsként, győződjön meg róla, hogy hozzáadott legalább egy kártyát a szolgáltatáshoz"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ha szeretné felvenni a QR-kód-szkennelőt gyorsparancsként, győződjön meg róla, hogy van az eszközre telepítve kameraalkalmazás"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ha szeretné felvenni Home appot gyorsparancsként, gondoskodjon az alkalmazás telepítéséről"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Legalább egy eszköz rendelkezésre áll"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Válassza ki az alapértelmezett jegyzetkészítő alkalmazást, amelyet a jegyzetelési gyorsparancshoz szeretne használni"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index e573682..7b72456 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Սահմանաչափ՝ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Աշխատանքային հավելվածներ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Դադարեցված է"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Գիշերային ռեժիմ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Կմիացվի մայրամուտին"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Մինչև լուսաբաց"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Խոշորացնել էկրանի որոշակի հատվածը"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Բացել խոշորացման կարգավորումները"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Փակել խոշորացման կարգավորումները"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Քաշեք անկյունը՝ չափը փոխելու համար"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Թույլատրել անկյունագծով ոլորումը"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Փոխել չափը"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Բացել <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet հավելվածի դյուրանցումն ավելացնելու համար համոզվեք, որ հավելվածը տեղադրված է"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet հավելվածի դյուրանցումն ավելացնելու համար համոզվեք, որ առնվազն մեկ քարտ ավելացված է"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR կոդերի սկաների դյուրանցումն ավելացնելու համար համոզվեք, որ տեսախցիկի հավելվածը տեղադրված է"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home հավելվածի դյուրանցումն ավելացնելու համար համոզվեք, որ հավելվածը տեղադրված է"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Հասանելի է առնվազն մեկ սարք"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Ընտրեք նշումների կանխադրված հավելված՝ նշումների ստեղծման դյուրանցումն օգտագործելու համար"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0e8c3a1..fc12a14 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Batas <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikasi kerja"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Dijeda"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Cahaya Malam"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aktif saat malam"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Sampai pagi"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buka setelan pembesaran"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Tutup setelan pembesaran"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Tarik pojok persegi untuk mengubah ukuran"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Izinkan scrolling diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ubah ukuran"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Untuk menambahkan aplikasi Wallet sebagai pintasan, pastikan aplikasi sudah diinstal"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Untuk menambahkan aplikasi Wallet sebagai pintasan, pastikan minimal satu kartu telah ditambahkan"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Untuk menambahkan pemindai kode QR sebagai pintasan, pastikan aplikasi kamera sudah diinstal"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Untuk menambahkan aplikasi Home sebagai pintasan, pastikan aplikasi sudah diinstal"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Tersedia minimal satu perangkat"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pilih aplikasi catatan default untuk menggunakan pintasan pembuatan catatan"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 8411db4..2c784a6 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hámark"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Vinnuforrit"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Hlé"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Næturljós"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Kveikt við sólsetur"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Til sólarupprásar"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Opna stillingar stækkunar"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Loka stillingum stækkunar"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dragðu horn til að breyta stærð"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Leyfa skáflettingu"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Breyta stærð"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Opna <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Til að bæta Veskisforritinu við sem flýtileið skaltu ganga úr skugga um að forritið sé uppsett"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Til að bæta Veskisforritinu við sem flýtileið skaltu ganga úr skugga um að hafa bætt að minnsta kosti einu korti við"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Til að bæta QR-kóðaskanna við sem flýtileið skaltu ganga úr skugga um að myndavélarforrit sé uppsett"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Til að bæta Home-forritinu við sem flýtileið skaltu ganga úr skugga um að forritið sé uppsett"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Að minnsta kosti eitt tæki er tiltækt"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Veldu sjálfgefið glósuforrit til að nota flýtileið fyrir glósugerð"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 561da81..7c22297 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite di <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"App di lavoro"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"In pausa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luminosità notturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Attivata al tramonto"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Fino all\'alba"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Apri le impostazioni di ingrandimento"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Chiudi impostazioni di ingrandimento"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Trascina l\'angolo per ridimensionare"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Scorrimento diagonale"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ridimensiona"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Apri <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Per aggiungere l\'app Wallet come scorciatoia, assicurati che l\'app sia installata"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Per aggiungere l\'app Wallet come scorciatoia, assicurati che sia stata aggiunta almeno una carta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Per aggiungere lo scanner di codici QR come scorciatoia, assicurati che ci sia un\'app fotocamera installata"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Per aggiungere l\'app Home come scorciatoia, assicurati che l\'app sia installata"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ci sia almeno un dispositivo disponibile"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Seleziona un\'app per le note predefinita per usare la scorciatoia per l\'aggiunta di note"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c905b04..f1dd497 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"הגבלה של <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"אזהרה – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"אפליקציות לעבודה"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"בהשהיה"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"תאורת לילה"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"התכונה מופעלת בשקיעה"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"עד הזריחה"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"פתיחת הגדרות ההגדלה"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"סגירת הגדרות ההגדלה"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"צריך לגרור את הפינה כדי לשנות את הגודל"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"הפעלת גלילה באלכסון"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"שינוי גודל"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"פתיחת <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"כדי להוסיף את אפליקציית Wallet כקיצור דרך, צריך לוודא שהאפליקציה מותקנת"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"כדי להוסיף את אפליקציית Wallet כקיצור דרך, צריך לוודא שנוסף לפחות כרטיס אחד"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"כדי להוסיף את סורק קודי ה-QR כקיצור דרך, צריך לוודא שמותקנת אפליקציית מצלמה"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"כדי להוסיף את אפליקציית Home כקיצור דרך, צריך לוודא שהאפליקציה מותקנת"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• יש לפחות מכשיר אחד זמין"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"צריך לבחור אפליקציית פתקים שתיפתח כברירת מחדל כשייעשה שימוש במקש הקיצור לכתיבת פתקים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8a40d71..5d3919e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"上限: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"仕事用アプリ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"一時停止中"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜間モード"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"日の入りに ON"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"日の出まで"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"画面の一部を拡大します"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"画面の拡大設定を開く"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"拡大の設定を閉じる"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"編集モードを終了"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"サイズを変更するには角をドラッグ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"斜めスクロールを許可"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"サイズ変更"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> を開く"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ウォレット アプリをショートカットとして追加するには、アプリがインストールされていることを確認してください"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ウォレット アプリをショートカットとして追加するには、カードが 1 枚以上追加されていることを確認してください"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR コードスキャナをショートカットとして追加するには、カメラアプリがインストールされていることを確認してください"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Google Home アプリをショートカットとして追加するには、アプリがインストールされていることを確認してください"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 利用できるデバイスが 1 台以上ある"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"メモのショートカットを使用するデフォルトのメモアプリを選択してください"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 0c5c76e..daa0ae7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"ლიმიტი: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"სამსახურის აპები"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"დაპაუზებულია"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ღამის განათება"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ჩაირთოს მზის ჩასვლისას"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"მზის ამოსვლამდე"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ეკრანის ნაწილის გადიდება"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"გახსენით გადიდების პარამეტრები"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"გადიდების პარამეტრების დახურვა"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"რედაქტირების რეჟიმიდან გასვლა"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ჩავლებით გადაიტანეთ კუთხე ზომის შესაცვლელად"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"დიაგონალური გადაადგილების დაშვება"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ზომის შეცვლა"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> აპის გახსნა"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"საფულის აპის მალსახმობის დასამატებლად დარწმუნდით, რომ აპი დაინსტალირებულია"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"საფულის აპის მალსახმობის დასამატებლად დარწმუნდით, რომ დამატებულია მინიმუმ ერთი ბარათი"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR კოდის სკანერის მალსახმობის დასამატებლად დარწმუნდით, რომ დაინსტალირებულია კამერის აპი"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"მთავარი აპის მალსახმობის დასამატებლად დარწმუნდით, რომ აპი დაინსტალირებულია"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ხელმისაწვდომია მინიმუმ ერთი მოწყობილობა"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"აირჩიეთ ჩანიშვნების ნაგულისხმევი აპი, რათა ჩანიშვნების შექმნის მალსახმობი გამოიყენოთ"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 953292d..18f7855 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> шегі"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Жұмыс қолданбалары"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Кідіртілген"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Түнгі жарық"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Күн батқанда қосу"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Күн шыққанға дейін"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ұлғайту параметрлерін ашу"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Ұлғайту параметрлерін жабу"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Өлшемін өзгерту үшін бұрышынан сүйреңіз."</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Диагональ бойынша айналдыруға рұқсат беру"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Өлшемін өзгерту"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ашу"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet қолданбасын таңбаша ретінде қосу үшін қолданбаның орнатылғанын тексеріңіз."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet қолданбасын таңбаша ретінде қосу үшін кемінде бір картаның қосылғанын тексеріңіз."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR кодының сканерін таңбаша ретінде қосу үшін камера қолданбасының орнатылғанын тексеріңіз."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home қолданбасын таңбаша ретінде қосу үшін қолданбаның орнатылғанын тексеріңіз."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Кемінде бір құрылғы қолжетімді."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Жазба жазу таңбашасын пайдалану үшін әдепкі жазба қолданбаны таңдаңыз."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 535400f..d5ef4b5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"ដែនកំណត់ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការព្រមាន"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"កម្មវិធីការងារ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"បានផ្អាក"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ពន្លឺពេលយប់"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"បើកនៅពេលថ្ងៃលិច"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"រហូតដល់ពេលថ្ងៃរះ"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"បើកការកំណត់ការពង្រីក"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"បិទការកំណត់ការពង្រីក"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"អូសជ្រុងដើម្បីប្ដូរទំហំ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"អនុញ្ញាតការរំកិលបញ្ឆិត"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ប្ដូរទំហំ"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"បើក <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ដើម្បីបញ្ចូលកម្មវិធី Wallet ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីត្រូវបានដំឡើង"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ដើម្បីបញ្ចូលកម្មវិធី Wallet ជាផ្លូវកាត់ សូមប្រាកដថាបានបញ្ចូលកាតយ៉ាងហោចណាស់មួយ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"ដើម្បីបញ្ចូលកម្មវិធីស្កេនកូដ QR ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីកាមេរ៉ាត្រូវបានដំឡើង"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"ដើម្បីបញ្ចូលកម្មវិធី Home ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីត្រូវបានដំឡើង"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ឧបករណ៍យ៉ាងតិចមួយអាចប្រើបាន"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ជ្រើសរើសកម្មវិធីកំណត់ចំណាំលំនាំដើម ដើម្បីប្រើផ្លូវកាត់សម្រាប់ការកត់ចំណាំ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0a2bb64..0b82b55 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ನೈಟ್ ಲೈಟ್"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ಸೂರ್ಯಾಸ್ತದಲ್ಲಿ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ಹಿಗ್ಗಿಸುವಿಕೆ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ಮ್ಯಾಗ್ನಿಫಿಕೇಶನ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಮುಚ್ಚಿರಿ"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"ಎಡಿಟ್ ಮೋಡ್ನಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ಮರುಗಾತ್ರಗೊಳಿಸಲು ಮೂಲೆಯನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ಡಯಾಗನಲ್ ಸ್ಕ್ರೋಲಿಂಗ್ ಅನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
@@ -1038,7 +1040,7 @@
<string name="game_status" msgid="1340694320630973259">"ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ಸ್ನೇಹಿತರು"</string>
<string name="empty_status" msgid="5938893404951307749">"ರಾತ್ರಿ ಚಾಟ್ ಮಾಡೋಣ!"</string>
- <string name="status_before_loading" msgid="1500477307859631381">"ವಿಷಯ ಶೀಘ್ರದಲ್ಲೇ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
+ <string name="status_before_loading" msgid="1500477307859631381">"ಕಂಟೆಂಟ್ ಶೀಘ್ರದಲ್ಲೇ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
<string name="missed_call" msgid="4228016077700161689">"ಮಿಸ್ಡ್ ಕಾಲ್"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್ಡೇಟ್ಗಳು"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ವಾಲೆಟ್ ಆ್ಯಪ್ ಅನ್ನು ಶಾರ್ಟ್ಕಟ್ ಆಗಿ ಸೇರಿಸಲು, ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ವಾಲೆಟ್ ಆ್ಯಪ್ ಅನ್ನು ಶಾರ್ಟ್ಕಟ್ ಆಗಿ ಸೇರಿಸಲು, ಕನಿಷ್ಠ ಒಂದು ಕಾರ್ಡ್ ಅನ್ನು ಸೇರಿಸಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನರ್ ಅನ್ನು ಶಾರ್ಟ್ಕಟ್ ಆಗಿ ಸೇರಿಸಲು, ಕ್ಯಾಮರಾ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ಆ್ಯಪ್ ಅನ್ನು ಶಾರ್ಟ್ಕಟ್ ಆಗಿ ಸೇರಿಸಲು, ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಆಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ಕನಿಷ್ಠ ಒಂದು ಸಾಧನ ಲಭ್ಯವಿದೆ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ನೋಟ್ಸ್ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಬಳಸಲು ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d267fed..ea7d5c2 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"한도: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"직장 앱"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"일시중지됨"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"야간 조명"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"일몰에"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"일출까지"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"확대 설정 열기"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"확대 설정 닫기"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"모서리를 드래그하여 크기 조절"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"대각선 스크롤 허용"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"크기 조절"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> 열기"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"월렛 앱을 바로가기로 추가하려면 앱이 설치되어 있는지 확인하세요."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"월렛 앱을 바로가기로 추가하려면 하나 이상의 카드가 추가되어 있는지 확인하세요."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR 코드 스캐너를 바로가기로 추가하려면 카메라 앱이 설치되어 있는지 확인하세요."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home 앱을 바로가기로 추가하려면 앱이 설치되어 있는지 확인하세요."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 1대 이상의 기기를 사용할 수 있습니다."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"메모 바로가기를 사용하려면 기본 메모 앱을 선택합니다."</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 768e8a5..cb9e67a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> чектөө"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Жумуш колдонмолору"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Тындырылды"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Түнкү режим"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Күн батканда күйөт"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Күн чыкканга чейин"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Чоңойтуу параметрлерин ачуу"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Чоңойтуу параметрлерин жабуу"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Өлчөмүн өзгөртүү үчүн бурчун сүйрөңүз"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Диагональ боюнча сыдырууга уруксат берүү"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Өлчөмүн өзгөртүү"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ачуу"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Капчык колдонмосун ыкчам баскыч катары кошуу үчүн колдонмону орнотуу керек"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Капчык колдонмосун ыкчам баскыч катары кошуу үчүн кеминде бир картаны кошуу керек"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR кодунун сканерин ыкчам баскыч катары кошуу үчүн камера колдонмосун орнотуу керек"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home колдонмосун ыкчам баскыч катары кошуу үчүн колдонмону орнотуу керек"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Кеминде бир түзмөк жеткиликтүү"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Эскертме жазуу ыкчам баскычын колдонуу үчүн демейки эскертме жазуу колдонмосун тандаңыз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index e8b4003..3e26137 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"ຈຳກັດ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"ຄຳເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ແອັບບ່ອນເຮັດວຽກ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ຢຸດໄວ້ຊົ່ວຄາວ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ແສງກາງຄືນ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ເປີດຕອນຕາເວັນຕົກ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ເປີດການຕັ້ງຄ່າການຂະຫຍາຍ"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ປິດການຕັ້ງຄ່າການຂະຫຍາຍ"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ລາກຢູ່ມຸມເພື່ອປັບຂະໜາດ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ອະນຸຍາດໃຫ້ເລື່ອນທາງຂວາງ"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ປ່ຽນຂະໜາດ"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"ເປີດ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ເພື່ອເພີ່ມແອັບ Wallet ເປັນທາງລັດ, ກະລຸນາກວດສອບໃຫ້ແນ່ໃຈວ່າໄດ້ຕິດຕັ້ງແອັບແລ້ວ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ເພື່ອເພີ່ມແອັ Wallet ເປັນທາງລັດ, ກະລຸນາກວດສອບໃຫ້ແນ່ໃຈວ່າໄດ້ເພີ່ມຢ່າງໜ້ອຍ 1 ບັດແລ້ວ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"ເພື່ອເພີ່ມຕົວສະແກນລະຫັດ QR ເປັນທາງລັດ, ກະລຸນາກວດສອບໃຫ້ແນ່ໃຈວ່າໄດ້ຕິດຕັ້ງແອັບກ້ອງຖ່າຍຮູບແລ້ວ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"ເພື່ອເພີ່ມແອັບ Home ເປັນທາງລັດ, ກະລຸນາກວດສອບໃຫ້ແນ່ໃຈວ່າໄດ້ຕິດຕັ້ງແອັບແລ້ວ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ມີຢ່າງໜ້ອຍ 1 ອຸປະກອນພ້ອມໃຫ້ນຳໃຊ້"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ເລືອກແອັບບັນທຶກເລີ່ມຕົ້ນເພື່ອໃຊ້ທາງລັດການຈົດບັນທຶກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2426533..a7d874c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limitas: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Darbo programos"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pristabdyta"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nakties šviesa"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Per saulėlydį"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Iki saulėtekio"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Atidaryti didinimo nustatymus"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Uždaryti didinimo nustatymus"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Norėdami keisti dydį, vilkite kampą"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Slinkimo įstrižai leidimas"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Pakeisti dydį"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atidaryti „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Jei norite pridėti programą „Wallet“ kaip šaukinį, įsitikinkite, kad programa įdiegta"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Jei norite pridėti programą „Wallet“ kaip šaukinį, įsitikinkite, kad pridėta bent viena kortelė"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Jei norite pridėti QR kodų skaitytuvą kaip šaukinį, įsitikinkite, kad fotoaparato programa įdiegta"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Jei norite pridėti programą „Home“ kaip šaukinį, įsitikinkite, kad programa įdiegta"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Pasiekiamas bent vienas įrenginys"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pasirinkite numatytąją užrašų programą, kuriai norite naudoti užrašų kūrimo šaukinį"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 9bda2b8..972380c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ierobežojums: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Darba lietotnes"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Darbība apturēta"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nakts režīms"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Saulrietā"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Līdz saullēktam"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Atvērt palielinājuma iestatījumus"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Aizvērt palielinājuma iestatījumus"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Velciet stūri, lai mainītu izmērus"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Atļaut ritināšanu pa diagonāli"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Mainīt lielumu"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atvērt lietotni <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Lai varētu pievienot lietotni Maks kā saīsni, lietotnei ir jābūt instalētai."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Lai varētu pievienot lietotni Maks kā saīsni, ir jābūt pievienotai vismaz vienai kartei."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Lai varētu pievienot lietotni Kvadrātkoda skeneris kā saīsni, ir jābūt instalētai kameras lietotnei."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Lai varētu pievienot lietotni Home kā saīsni, lietotnei ir jābūt instalētai."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ir pieejama vismaz viena ierīce."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Atlasiet noklusējuma piezīmju lietotni, lai izmantotu piezīmju pierakstīšanas saīsni."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 9b8b04c..4b1e5a8 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Лимит: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Предупредување: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Работни апликации"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Паузирано"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ноќно светло"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Вклуч. на зајдисонце"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До изгрејсонце"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголемувајте дел од екранот"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори поставки за зголемување"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Затворете ги поставките за зголемување"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Повлечете на аголот за да ја промените големината"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволете дијагонално лизгање"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Промени големина"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворете ја <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"За да ја додадете апликацијата Wallet како кратенка, апликацијата мора да е инсталирана"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"За да ја додадете апликацијата Wallet како кратенка, мора да имате додадено најмалку една картичка"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"За да го додадете скенерот на QR-кодови како кратенка, погрижете се дека имате инсталирано апликација за камера"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"За да ја додадете апликацијата Home како кратенка, апликацијата мора да е инсталирана"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• достапен е најмалку еден уред"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Изберете стандардна апликација за белешки за да ја користите кратенката за фаќање белешки"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index b7a03d8..7202f5e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> പരിധി"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ഔദ്യോഗിക ആപ്പുകൾ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"തൽക്കാലം നിർത്തി"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"നൈറ്റ് ലൈറ്റ്"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"സൂര്യാസ്തമയത്തിന്"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"സൂര്യോദയം വരെ"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"മാഗ്നിഫിക്കേഷൻ ക്രമീകരണം തുറക്കുക"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"മാഗ്നിഫിക്കേഷൻ ക്രമീകരണം അടയ്ക്കുക"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"എഡിറ്റ് മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"വലുപ്പം മാറ്റാൻ മൂല വലിച്ചിടുക"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ഡയഗണൽ സ്ക്രോളിംഗ് അനുവദിക്കുക"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"വലുപ്പം മാറ്റുക"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> തുറക്കുക"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"കുറുക്കുവഴിയായി Wallet ആപ്പ് ചേർക്കാൻ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"കുറുക്കുവഴിയായി Wallet ആപ്പ് ചേർക്കാൻ, ഒരു കാർഡെങ്കിലും ചേർത്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"കുറുക്കുവഴിയായി QR കോഡ് സ്കാനർ ചേർക്കാൻ, ക്യാമറാ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"കുറുക്കുവഴിയായി Home ആപ്പ് ചേർക്കാൻ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ഒരു ഉപകരണമെങ്കിലും ലഭ്യമാണ്"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"കുറിപ്പ് രേഖപ്പെടുത്തൽ കുറുക്കുവഴി ഉപയോഗിക്കുന്നതിന് ഒരു ഡിഫോൾട്ട് കുറിപ്പ് ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 7a2ca61..470e0fd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> хязгаар"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Ажлын аппууд"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Түр зогсоосон"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Шөнийн гэрэл"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Нар жаргах үед"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Нар мандах хүртэл"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Томруулах тохиргоог нээх"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Томруулах тохиргоог хаах"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Хэмжээг өөрчлөхийн тулд булангаас чирнэ үү"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Хөндлөн гүйлгэхийг зөвшөөрөх"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Хэмжээг өөрчлөх"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>-г нээх"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet аппыг товчлолоор нэмэхийн тулд уг аппыг суулгасан эсэхийг шалгана уу"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet аппыг товчлолоор нэмэхийн тулд дор хаяж нэг карт нэмсэн эсэхийг шалгана уу"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR код сканнерыг товчлолоор нэмэхийн тулд камерын аппыг суулгасан эсэхийг шалгана уу"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home аппыг товчлолоор нэмэхийн тулд уг аппыг суулгасан эсэхийг шалгана уу"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Дор хаяж нэг төхөөрөмж боломжтой"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Тэмдэглэл хөтлөх товчлолыг ашиглахын тулд тэмдэглэлийн өгөгдмөл аппыг сонгоно уу"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index ccbc209..f5abe78 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"कामाशी संबंधित अॅप्स"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"थांबवले आहे"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"रात्रीचा प्रकाश"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"संध्याकाळी सुरू असते"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयापर्यंत"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"मॅग्निफिकेशन सेटिंग्ज उघडा"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"मॅग्निफिकेशन सेटिंग्ज बंद करा"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"आकार बदलण्यासाठी कोपरा ड्रॅग करा"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"तिरपे स्क्रोल करण्याची अनुमती द्या"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"आकार बदला"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> उघडा"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ॲप शॉर्टकट म्हणून जोडण्यासाठी ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ॲप शॉर्टकट म्हणून जोडण्यासाठी किमान एक कार्ड जोडले असल्याची खात्री करा"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR कोड स्कॅनर शॉर्टकट म्हणून जोडण्यासाठी कॅमेरा ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home अॅप शॉर्टकट म्हणून जोडण्यासाठी ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• किमान एक डिव्हाइस उपलब्ध करणे"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"टिपा घेण्यासंबंधित शॉर्टकट वापरण्याकरिता टिपांसाठीचे डीफॉल्ट अॅप निवडा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 586c96e..6b74c43 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Apl kerja"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Dijeda"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Cahaya Malam"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Dihidupkan pd senja"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hingga matahari terbit"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buka tetapan pembesaran"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Tutup tetapan pembesaran"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Keluar daripada mod edit"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Seret sudut untuk mengubah saiz"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Benarkan penatalan pepenjuru"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ubah saiz"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Untuk menambahkan apl Wallet sebagai pintasan, pastikan apl telah dipasang"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Untuk menambahkan apl Wallet sebagai pintasan, pastikan sekurang-kurangnya satu kad telah ditambahkan"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Untuk menambahkan pengimbas kod QR sebagai pintasan, pastikan apl kamera telah dipasang"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Untuk menambahkan apl Home sebagai pintasan, pastikan apl telah dipasang"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Sekurang-kurangnya satu peranti tersedia"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pilih apl nota lalai untuk menggunakan pintasan pengambilan nota"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index aa5853f..2e2567d 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ကန့်သတ်ချက်"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"အလုပ်သုံးအက်ပ်များ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ခဏရပ်ထားသည်"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ညအလင်းရောင်"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"နေဝင်ချိန်၌ ဖွင့်ရန်"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"နေထွက်ချိန် အထိ"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ချဲ့ခြင်း ဆက်တင်များ ဖွင့်ရန်"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ချဲ့ခြင်း ဆက်တင်များ ပိတ်ရန်"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"ပြင်ဆင်မုဒ်မှ ထွက်ရန်"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"အရွယ်အစားပြန်ပြုပြင်ရန် ထောင့်စွန်းကို ဖိဆွဲပါ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ထောင့်ဖြတ် လှိမ့်ခွင့်ပြုရန်"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"အရွယ်အစားပြန်ပြုပြင်ရန်"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ဖွင့်ရန်"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ၎င်းအားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် အနည်းဆုံး ကတ်တစ်ခုထည့်ထားကြောင်း သေချာပါစေ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR ကုဒ် စကင်ဖတ်စနစ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ကင်မရာအက်ပ်အားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ၎င်းအားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• အနည်းဆုံး စက်တစ်ခုသုံးနိုင်ရမည်"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"မှတ်စုရေးသည့် ဖြတ်လမ်းလင့်ခ်သုံးရန်အတွက် မူရင်းမှတ်စုများအက်ပ် ရွေးရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 90025c6..8ef7794 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Grense på <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Jobbapper"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Satt på pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nattlys"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"På ved solnedgang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Til soloppgang"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Åpne innstillinger for forstørring"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Lukk forstørringsinnstillingene"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dra hjørnet for å endre størrelse"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillat diagonal rulling"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Endre størrelse"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åpne <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"For å legge til Wallet-appen som snarvei, sørg for at appen er installert"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"For å legge til Wallet-appen som snarvei, sørg for at minst ett kort er lagt til"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"For å legge til QR-kodeskanneren som snarvei, sørg for at du har en kameraapp installert"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"For å legge til Home-appen som snarvei, sørg for at appen er installert"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• minst én enhet er tilgjengelig"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Velg en standard notatapp du vil bruke med notatsnarveien"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index dd15313..c56ebb6 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"कामसम्बन्धी एपहरू"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"पज गरिएको छ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"सूर्यास्तमा सक्रिय"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयसम्म"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"जुम इनसम्बन्धी सेटिङ खोल्नुहोस्"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"जुम इन गर्ने सुविधाको सेटिङ बन्द गर्नुहोस्"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"आकार बदल्न कुनाबाट ड्र्याग गर्नुहोस्"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"डायगोनल तरिकाले स्क्रोल गर्ने अनुमति दिनुहोस्"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"आकार बदल्नुहोस्"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोल्नुहोस्"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"सर्टकटका रूपमा Wallet एप हाल्न उक्त एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"सर्टकटका रूपमा Wallet एप हाल्न कम्तीमा एउटा कार्ड हालिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"सर्टकटका रूपमा QR कोड स्क्यानर हाल्न क्यामेरा एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home एपलाई सर्टकटका रूपमा हाल्न उक्त एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• कम्तीमा एउटा डिभाइस उपलब्ध छ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"नोट बनाउनेसम्बन्धी सर्टकट प्रयोग गर्न नोट बनाउने डिफल्ट एप चयन गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1b657c9..088bcbd 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limiet van <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Werk-apps"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Onderbroken"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nachtverlichting"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan bij zonsondergang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopkomst"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Instellingen voor vergroting openen"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Instellingen voor vergroting sluiten"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Bewerkingsmodus sluiten"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Sleep een hoek om het formaat te wijzigen"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonaal scrollen toestaan"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Formaat aanpassen"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> openen"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Als je de Wallet-app wilt toevoegen als sneltoets, zorg je dat de app is geïnstalleerd"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Als je de Wallet-app wilt toevoegen als sneltoets, zorg je dat er minstens één kaart is toegevoegd"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Als je de QR-codescanner wilt toevoegen als sneltoets, zorg je dat er een camera-app is geïnstalleerd"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Als je de Home-app wilt toevoegen als sneltoets, zorg je dat de app is geïnstalleerd"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Er is minstens één apparaat beschikbaar"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecteer een standaard notitie-app om de sneltoets voor notities maken te gebruiken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3da07a8..64955e4 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ସୀମା"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ଚେତାବନୀ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ୱାର୍କ ଆପ୍ସ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ବିରତ କରାଯାଇଛି"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ନାଇଟ୍ ଲାଇଟ୍"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ସୂର୍ଯ୍ୟାସ୍ତ ବେଳେ ଅନ୍ ହେବ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ସୂର୍ଯ୍ୟୋଦୟ ପର୍ଯ୍ୟନ୍ତ"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ମାଗ୍ନିଫିକେସନ ସେଟିଂସ ଖୋଲନ୍ତୁ"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ମେଗ୍ନିଫିକେସନ ସେଟିଂସକୁ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ରିସାଇଜ କରିବା ପାଇଁ କୋଣକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ଡାଏଗୋନାଲ ସ୍କ୍ରୋଲିଂକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ରିସାଇଜ କରନ୍ତୁ"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ଏକ ସର୍ଟକଟ ଭାବେ Wallet ଆପ ଯୋଗ କରିବା ପାଇଁ ଏହି ଆପ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ଏକ ସର୍ଟକଟ ଭାବେ Wallet ଆପ ଯୋଗ କରିବାକୁ ଅତିକମରେ ଗୋଟିଏ ଆପ ଯୋଗ କରାଯାଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"ଏକ ସର୍ଟକଟ ଭାବେ QR କୋଡ ସ୍କାନର ଯୋଗ କରିବାକୁ ଏକ କେମେରା ଆପ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"ଏକ ସର୍ଟକଟ ଭାବେ Home ଆପ ଯୋଗ କରିବା ପାଇଁ ଏହି ଆପ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ଅତିକମରେ ଗୋଟିଏ ଡିଭାଇସ ଉପଲବ୍ଧ ଅଛି"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ନୋଟଟେକିଂ ସର୍ଟକଟ ବ୍ୟବହାର କରିବାକୁ ଏକ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ୍ସ ଚୟନ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index b8a92c2..b3d4482 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ਰੋਕਿਆ ਗਿਆ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ਰਾਤ ਦੀ ਰੋਸ਼ਨੀ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ਸੂਰਜ ਛਿਪਣ \'ਤੇ ਚਾਲੂ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ਸਕ੍ਰੀਨ ਦੇ ਹਿੱਸੇ ਨੂੰ ਵੱਡਾ ਕਰੋ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸੈਟਿੰਗਾਂ ਬੰਦ ਕਰੋ"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ਆਕਾਰ ਬਦਲਣ ਲਈ ਕੋਨਾ ਘਸੀਟੋ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ਟੇਡੀ ਦਿਸ਼ਾ ਵਿੱਚ ਸਕ੍ਰੋਲ ਕਰਨ ਦਿਓ"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ਆਕਾਰ ਬਦਲੋ"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ਐਪ ਨੂੰ ਸ਼ਾਰਟਕੱਟ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਪੱਕਾ ਕਰੋ ਕਿ ਐਪ ਸਥਾਪਤ ਹੈ"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ਐਪ ਨੂੰ ਸ਼ਾਰਟਕੱਟ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਪੱਕਾ ਕਰੋ ਕਿ ਘੱਟੋ-ਘੱਟ ਇੱਕ ਕਾਰਡ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR ਕੋਡ ਸਕੈਨਰ ਨੂੰ ਸ਼ਾਰਟਕੱਟ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਪੱਕਾ ਕਰੋ ਕਿ ਕੈਮਰਾ ਐਪ ਸਥਾਪਤ ਹੈ"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ਐਪ ਨੂੰ ਸ਼ਾਰਟਕੱਟ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਪੱਕਾ ਕਰੋ ਕਿ ਐਪ ਸਥਾਪਤ ਹੈ"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ਘੱਟੋ-ਘੱਟ ਇੱਕ ਡੀਵਾਈਸ ਉਪਲਬਧ ਹੈ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ਨੋਟ ਬਣਾਉਣ ਵਾਲੇ ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਚੁਣੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8c0a78e..e3beef0 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikacje służbowe"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Wstrzymano"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Podświetlenie nocne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Włącz o zachodzie"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do wschodu słońca"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otwórz ustawienia powiększenia"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zamknij ustawienia powiększenia"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Przeciągnij róg, aby zmienić rozmiar"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Zezwalaj na przewijanie poprzeczne"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Zmień rozmiar"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otwórz: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Aby dodać aplikację Portfel jako skrót, upewnij się, że jest zainstalowana"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Aby dodać aplikację Portfel jako skrót, upewnij się, że została dodana co najmniej 1 karta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Aby dodać Skaner kodów QR jako skrót, upewnij się, że jest zainstalowana aplikacja aparatu"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Aby dodać aplikację Home jako skrót, upewnij się, że jest zainstalowana"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostępne jest co najmniej 1 urządzenie."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Wybierz domyślną aplikację do obsługi notatek, której skrótu będziesz używać do funkcji notowania"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index bf976f7..8f5d7fa 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Apps de trabalho"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausado"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Modo noturno"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ativ. ao pôr do sol"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Até o nascer do sol"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir as configurações de ampliação"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fechar configurações de ampliação"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Sair do modo de edição"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arraste o canto para redimensionar"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir rolagem diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionar"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar o app Carteira como um atalho, verifique se ele está instalado"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar o app Carteira como um atalho, verifique se pelo menos um cartão foi adicionado"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o leitor de código QR como um atalho, verifique se algum app de câmera está instalado"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar o app Home como um atalho, verifique se ele está instalado"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Pelo menos um dispositivo está disponível"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9974df1..a4f17b6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Apps trabalho"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausado"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luz noturna"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ativ. ao pôr-do-sol"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Até ao amanhecer"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir definições de ampliação"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fechar definições de ampliação"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Sair do modo de edição"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastar o canto para redimensionar"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir deslocamento da página na diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionar"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar a app Carteira como um atalho, certifique-se de que a app está instalada"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar a app Carteira como um atalho, certifique-se de que foi adicionado, pelo menos, um cartão"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o Leitor de códigos QR como um atalho, certifique-se de que está instalada uma app de câmara"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar a app Home como um atalho, certifique-se de que a app está instalada"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Está disponível, pelo menos, um dispositivo"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione uma app de notas predefinida para usar o atalho de anotação"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index bf976f7..8f5d7fa 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Apps de trabalho"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausado"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Modo noturno"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ativ. ao pôr do sol"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Até o nascer do sol"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir as configurações de ampliação"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fechar configurações de ampliação"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Sair do modo de edição"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arraste o canto para redimensionar"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir rolagem diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionar"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar o app Carteira como um atalho, verifique se ele está instalado"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar o app Carteira como um atalho, verifique se pelo menos um cartão foi adicionado"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o leitor de código QR como um atalho, verifique se algum app de câmera está instalado"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar o app Home como um atalho, verifique se ele está instalado"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Pelo menos um dispositivo está disponível"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1ed3a37..749106b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limită de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplicații pentru lucru"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Întreruptă"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Lumină de noapte"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Activată la apus"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Până la răsărit"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Mărește o parte a ecranului"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Deschide setările pentru mărire"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Închide setările de mărire"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Trage de colț pentru a redimensiona"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permite derularea pe diagonală"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Redimensionează"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Deschide <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pentru a adăuga aplicația Portofel drept comandă rapidă, asigură-te că aplicația este instalată"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pentru a adăuga aplicația Portofel drept comandă rapidă, asigură-te că ai adăugat cel puțin un card"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pentru a adăuga Scanner de coduri QR drept comandă rapidă, asigură-te că este instalată o aplicație pentru camera foto"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pentru a adăuga aplicația Home drept comandă rapidă, asigură-te că aplicația este instalată"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Este disponibil cel puțin un dispozitiv"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selectează o aplicație prestabilită pentru note ca să folosești comanda rapidă de luat note"</string>
@@ -1167,7 +1169,7 @@
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
<string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
<string name="privacy_dialog_title" msgid="7839968133469098311">"Microfon și cameră"</string>
- <string name="privacy_dialog_summary" msgid="2458769652125995409">"Folosit recent de aplicații"</string>
+ <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilizare recentă în aplicații"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vezi accesarea recentă"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"Gata"</string>
<string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Extinde și afișează opțiunile"</string>
@@ -1178,10 +1180,10 @@
<string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Gestionează accesul"</string>
<string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Folosit de un apel telefonic"</string>
<string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Folosit recent într-un apel telefonic"</string>
- <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Folosit de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Folosit de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
+ <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Se folosește pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"S-a folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Se folosește pentru <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
- <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Folosit de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
+ <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Se folosește pentru <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 400db7b..5f7445a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ограничение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Рабочие приложения"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Приостановлен"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ночная подсветка"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Вкл. на закате"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До рассвета"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Открыть настройки увеличения"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Закрыть настройки увеличения"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Потяните за угол, чтобы изменить размер"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Разрешить прокручивать по диагонали"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Изменить размер"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Открыть \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Вы можете добавить ярлык приложения \"Кошелек\", только если оно установлено."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Вы можете добавить ярлык приложения \"Кошелек\", только если добавлена хотя бы одна карта."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Вы можете добавить ярлык сканера QR-кодов, только если установлено приложение камеры."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Вы можете добавить ярлык приложения Home, только если оно установлено."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Доступно хотя бы одно устройство."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Выберите стандартное приложение для заметок, которое будет открываться при нажатии на ярлык."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 37a14f9..5cc1fa9 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> සීමිත"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"කාර්යාල යෙදුම්"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"විරාමයි"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"රාත්රී ආලෝකය"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"හිරු බැසීමේදී ක්රි."</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"හිරු නගින තෙක්"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"විශාලන සැකසීම් විවෘත කරන්න"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"විශාලන සැකසීම් වසන්න"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ප්රමාණය වෙනස් කිරීමට කොන අදින්න"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"විකර්ණ අනුචලනයට ඉඩ දෙන්න"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ප්රතිප්රමාණය කරන්න"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> විවෘත කරන්න"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"කෙටිමඟක් ලෙස Wallet යෙදුම එක් කිරීම සඳහා, යෙදුම ස්ථාපනය කර ඇති බවට වග බලා ගන්න"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"කෙටිමඟක් ලෙස Wallet යෙදුම එක් කිරීම සඳහා, අවම වශයෙන් එක් කාඩ්පතක් එක් කර ඇති බවට වග බලා ගන්න"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"කෙටිමඟක් ලෙස QR කේත ස්කෑනරය එක් කිරීම සඳහා, කැමරා යෙදුමක් ස්ථාපනය කර ඇති බවට වග බලා ගන්න"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home යෙදුම කෙටිමඟක් ලෙස එක් කිරීම සඳහා, යෙදුම ස්ථාපනය කර ඇති බව සහතික කර ගන්න"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• අවම වශයෙන් එක උපාංගයක් ලැබේ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"සටහන් ගැනීමේ කෙටිමඟ භාවිතා කිරීමට පෙරනිමි සටහන් යෙදුමක් තෝරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index baa9b4f..1da7aca 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Pracovné aplikácie"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pozastavené"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nočný režim"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Zapne sa pri západe slnka"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do východu slnka"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvoriť nastavenia zväčšenia"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zavrieť nastavenia zväčšenia"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Veľkosť zmeníte presunutím rohu"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Povoliť diagonálne posúvanie"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Zmeniť veľkosť"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvoriť <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ak chcete pridať aplikáciu Peňaženka ako odkaz, uistite sa, že je nainštalovaná"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ak chcete pridať aplikáciu Peňaženka ako odkaz, uistite sa, že bola pridaná aspoň jedna karta"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ak chcete pridať skener QR kódov ako odkaz, uistite, že je nainštalovaná aplikácia fotoaparátu"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ak chcete pridať aplikáciu Home ako odkaz, uistite sa, že je nainštalovaná"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• K dispozícii je minimálne jedno zariadenie"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Ak chcete používať odkaz na písanie poznámok, vyberte predvolenú aplikáciu na písanie poznámok"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 3608293..79e5437 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Omejitev: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Delovne aplikacije"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Začasno zaustavljeno"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nočna svetloba"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ob sončnem zahodu"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do sončnega vzhoda"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Odpri nastavitve povečave"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Zapri nastavitve povečave"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Zapri način za urejanje"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Povlecite vogal, da spremenite velikost."</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dovoli diagonalno pomikanje"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Spremeni velikost"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Odpri aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Če želite aplikacijo Denarnica dodati kot bližnjico, poskrbite, da je aplikacija nameščena."</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Če želite aplikacijo Denarnica dodati kot bližnjico, poskrbite, da je dodana vsaj ena kartica."</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Če želite optični bralnik kod QR dodati kot bližnjico, poskrbite, da je nameščena fotografska aplikacija."</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Če želite aplikacijo Home dodati kot bližnjico, poskrbite, da je aplikacija nameščena."</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Na voljo mora biti vsaj ena naprava."</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Izberite privzeto aplikacijo za zapiske, ki jo želite povezati z bližnjico do ustvarjanja zapiskov."</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 6e1edff..5b58fc7 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Kufiri: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikacionet e punës"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Vendosur në pauzë"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Drita e natës"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Në perëndim të diellit"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Deri në lindje të diellit"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zmadho një pjesë të ekranit"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Hap cilësimet e zmadhimit"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Mbyll cilësimet e zmadhimit"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Zvarrit këndin për të ndryshuar përmasat"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Lejo lëvizjen diagonale"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ndrysho përmasat"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Hap \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Për të shtuar aplikacionin \"Portofoli\" si një shkurtore, sigurohu që aplikacioni të jetë i instaluar"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Për të shtuar aplikacionin \"Portofoli\" si një shkurtore, sigurohu që të jetë shtuar të paktën një kartë"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Për të shtuar skanerin e kodeve QR si një shkurtore, sigurohu që aplikacioni i kamerës të jetë i instaluar"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Për të shtuar aplikacionin Home si një shkurtore, sigurohu që aplikacioni të jetë i instaluar"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ofrohet të paktën një pajisje"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Zgjidh një aplikacion të parazgjedhur shënimesh për të përdorur shkurtoren e mbajtjes së shënimeve"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0a73cf5..eee0fe6 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ограничење од <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Пословне апликације"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Паузирано"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ноћно светло"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Укључује се по заласку сунца"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До изласка сунца"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори подешавања увећања"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Затвори подешавања увећања"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Затвори режим измене"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Превуците угао да бисте променили величину"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволи дијагонално скроловање"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Промени величину"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворите: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Да бисте додали апликацију Новчаник као пречицу, уверите се да је апликација инсталирана"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Да бисте додали апликацију Новчаник као пречицу, уверите се да је додата бар једна картица"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Да бисте додали Скенер QR кода као пречицу, уверите се да је апликација за камеру инсталирана"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Да бисте додали апликацију Home као пречицу, уверите се да је апликација инсталирана"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Доступан је бар један уређај"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Изаберите подразумевану апликацију за белешке да бисте користили пречицу за прављење белешки"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 9329e19..b996649 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Gräns: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Jobbappar"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausad"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nattljus"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"På från solnedgången"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Till soluppgången"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Öppna inställningarna för förstoring"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Stäng inställningarna för förstoring"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dra i hörnet för att ändra storlek"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillåt diagonal scrollning"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Ändra storlek"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Öppna <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Se till att Wallet-appen är installerad om du vill lägga till den som genväg"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Se till att minst ett kort har lagts till om du vill lägga till Wallet-appen som genväg"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Se till att en kameraapp är installerad om du vill lägga till QR-skannern som genväg"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Se till att Home-appen är installerad om du vill lägga till den som genväg"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• minst en enhet är tillgänglig"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Välj en standardapp för anteckningar om du vill använda genvägen för anteckningar"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7c0df30..b00f9b6 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"kikomo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Programu za kazini"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Umesitishwa"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Mwanga wa Usiku"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Itawashwa machweo"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hadi macheo"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Fungua mipangilio ya ukuzaji"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Funga mipangilio ya ukuzaji"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Buruta kona ili ubadilishe ukubwa"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Ruhusu usogezaji wa kimshazari"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Badilisha ukubwa"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Fungua <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ili uweke programu ya Pochi kuwa njia ya mkato, hakikisha umesakinisha programu hiyo"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ili uweke programu ya Pochi kuwa njia ya mkato, hakikisha umeweka angalau kadi moja"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ili uweke kichanganuzi cha msimbo wa QR kuwa njia ya mkato, hakikisha umesakinisha programu ya kamera"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ili uweke programu ya Google Home kuwa njia ya mkato, hakikisha umesakinisha programu hiyo"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Angalau kifaa kimoja kinapatikana"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Chagua programu chaguomsingi ya madokezo ili utumie njia ya mkato ya kuandika madokezo"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index d85e012..915dcdb 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -82,6 +82,8 @@
<!-- start padding is smaller to account for status icon margins coming from drawable itself -->
<dimen name="shade_header_system_icons_padding_start">3dp</dimen>
<dimen name="shade_header_system_icons_padding_end">4dp</dimen>
+ <dimen name="shade_header_system_icons_padding_top">2dp</dimen>
+ <dimen name="shade_header_system_icons_padding_bottom">2dp</dimen>
<!-- Lockscreen shade transition values -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 4c6816b..57f537f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> வரம்பு"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"பணி ஆப்ஸ்"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"இடைநிறுத்தப்பட்டது"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"நைட் லைட்"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"மாலையில் ஆன் செய்"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"காலை வரை"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"பெரிதாக்கல் அமைப்புகளைத் திற"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"பெரிதாக்கல் அமைப்புகளை மூடுக"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"அளவை மாற்ற மூலையை இழுக்கவும்"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"குறுக்கே ஸ்க்ரோல் செய்வதை அனுமதி"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"அளவை மாற்று"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸைத் திற"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ஆப்ஸை ஷார்ட்கட்டாகச் சேர்க்க, அந்த ஆப்ஸ் நிறுவப்பட்டுள்ளதை உறுதிசெய்துகொள்ளவும்"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ஆப்ஸை ஷார்ட்கட்டாகச் சேர்க்க, அதில் குறைந்தது ஒரு கார்டாவது சேர்க்கப்பட்டுள்ளதை உறுதிசெய்துகொள்ளவும்"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR குறியீடு ஸ்கேனரை ஷார்ட்கட்டாகச் சேர்க்க, கேமரா ஆப்ஸ் நிறுவப்பட்டுள்ளதை உறுதிசெய்துகொள்ளவும்"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ஆப்ஸை ஷார்ட்கட்டாகச் சேர்க்க, அந்த ஆப்ஸ் நிறுவப்பட்டுள்ளதை உறுதிசெய்துகொள்ளவும்"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• குறைந்தபட்சம் ஒரு சாதனமாவது இருக்கிறது"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"குறிப்பெடுத்தல் ஷார்ட்கட்டைப் பயன்படுத்த, குறிப்பெடுப்பதற்கான இயல்புநிலை ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index f501d32..124f273 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> పరిమితి"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"వర్క్ యాప్లు"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"పాజ్ చేయబడింది"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"రాత్రి కాంతి"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"సూర్యాస్తమయానికి"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"సూర్యోదయం వరకు"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మ్యాగ్నిఫై చేయండి"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"మ్యాగ్నిఫికేషన్ సెట్టింగ్లను తెరవండి"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"మాగ్నిఫికేషన్ సెట్టింగ్లను మూసివేయండి"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"సవరణ మోడ్ నుండి ఎగ్జిట్ అవ్వండి"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"సైజ్ మార్చడానికి మూలను లాగండి"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"డయాగనల్ స్క్రోలింగ్ను అనుమతించండి"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"సైజ్ మార్చండి"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>ను తెరవండి"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, కనీసం ఒక కార్డ్ జోడించబడిందని నిర్ధారించుకోండి"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR కోడ్ స్కానర్ను షార్ట్కట్గా జోడించడానికి, కెమెరా యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• కనీసం ఒక పరికరమైనా అందుబాటులో ఉందని"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"నోట్టేకింగ్ షార్ట్కట్ను ఉపయోగించడానికి ఆటోమేటిక్ సెట్టింగ్ నోట్స్ యాప్ను ఎంచుకోండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7c524d9..46fec04 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"ขีดจำกัด <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"แอปงาน"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"หยุดชั่วคราว"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"แสงตอนกลางคืน"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"เปิดตอนพระอาทิตย์ตก"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"จนพระอาทิตย์ขึ้น"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ขยายบางส่วนของหน้าจอ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"เปิดการตั้งค่าการขยาย"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"ปิดการตั้งค่าการขยาย"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"ออกจากโหมดแก้ไข"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ลากที่มุมเพื่อปรับขนาด"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"อนุญาตการเลื่อนแบบทแยงมุม"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ปรับขนาด"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"เปิด <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"หากต้องการเพิ่มแอป Wallet เป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปแล้ว"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"หากต้องการเพิ่มแอป Wallet เป็นทางลัด โปรดตรวจสอบว่าได้เพิ่มบัตรอย่างน้อย 1 ใบแล้ว"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"หากต้องการเพิ่มเครื่องมือสแกนคิวอาร์โค้ดเป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปกล้องแล้ว"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"หากต้องการเพิ่มแอป Home เป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปแล้ว"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• มีอุปกรณ์พร้อมใช้งานอย่างน้อย 1 รายการ"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"เลือกแอปโน้ตเริ่มต้นเพื่อใช้ทางลัดการจดบันทึก"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fc2d8cf..079bd9b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ang limitasyon"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Mga app para sa trabaho"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Naka-pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Mao-on sa sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hanggang sunrise"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buksan ang mga setting ng pag-magnify"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Isara ang mga setting ng pag-magnify"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"I-drag ang sulok para i-resize"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Payagan ang diagonal na pag-scroll"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"I-resize"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buksan ang <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para maidagdag ang Wallet app bilang shortcut, siguraduhing naka-install ang app"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para maidagdag ang Wallet app bilang shortcut, siguraduhing may naidagdag na kahit isang card man lang"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para maidagdag ang scanner ng QR code bilang shortcut, siguraduhing may naka-install na camera app"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para maidagdag ang Home app bilang shortcut, siguraduhing naka-install ang app"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• May kahit isang device na available"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pumili ng default na app ng mga tala para magamit ang shortcut sa paggawa ng tala"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 803acae..7ba95ec 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Sınır: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"İş uygulamaları"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Duraklatıldı"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Gece Işığı"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Gün batımı açılacak"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Sabaha kadar"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Büyütme ayarlarını aç"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Büyütme ayarlarını kapat"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Yeniden boyutlandırmak için köşeyi sürükleyin"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Çapraz kaydırmaya izin ver"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Yeniden boyutlandır"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasını aç"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Cüzdan uygulamasını kısayol olarak eklemek için uygulamanın yüklü olduğundan emin olun"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Cüzdan uygulamasını kısayol olarak eklemek için en az bir kart eklendiğinden emin olun"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR kodu tarayıcıyı kısayol olarak eklemek için bir kamera uygulamasının yüklü olduğundan emin olun"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home uygulamasını kısayol olarak eklemek için uygulamanın yüklü olduğundan emin olun"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• En az bir cihaz mevcut olmalıdır"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Not alma kısayolunu kullanmak için varsayılan bir notlar uygulaması seçin"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 668fb59..3feefef 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Обмеження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Робочі додатки"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Призупинено"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Нічний екран"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Вмикається ввечері"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До сходу сонця"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Відкрити налаштування збільшення"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Закрити налаштування збільшення"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Потягніть кут, щоб змінити розмір"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволити прокручування по діагоналі"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Змінити розмір"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Відкрити <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Щоб додати ярлик для запуску додатка Google Гаманець, переконайтеся, що додаток установлено"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Щоб додати ярлик для запуску додатка Google Гаманець, переконайтеся, що він містить дані принаймні однієї картки"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Щоб додати ярлик для запуску сканера QR-коду, переконайтеся, що встановлено додаток для камери"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Щоб додати ярлик для запуску додатка Google Home, переконайтеся, що додаток установлено"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Принаймні один пристрій доступний"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Виберіть стандартний додаток для нотаток, щоб створювати їх за допомогою ярлика"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 33d11d9..29d3762 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> حد"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"دفتری ایپس"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"موقوف ہے"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"نائٹ لائٹ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"غروب آفتاب کے وقت آن ہوگی"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"طلوع آفتاب تک"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"اسکرین کا حصہ بڑا کریں"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"میگنیفکیشن کی ترتیبات کھولیں"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"میگنیفکیشن کی ترتیبات بند کریں"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"سائز تبدیل کرنے کے لیے کونے کو گھسیٹیں"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"وتری سکرولنگ کی اجازت دیں"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"سائز تبدیل کریں"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> کھولیں"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"والٹ ایپ کو شارٹ کٹ کے طور پر شامل کرنے کے لیے، یقینی بنائیں کہ ایپ انسٹال ہے"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"والٹ ایپ کو شارٹ کٹ کے طور پر شامل کرنے کے لیے، یقینی بنائیں کہ کم از کم ایک کارڈ شامل کیا گیا ہے"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR کوڈ اسکینر کو شارٹ کٹ کے طور پر شامل کرنے کے لیے، یقینی بنائیں کہ کیمرا ایپ انسٹال ہے"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"ہوم ایپ کو شارٹ کٹ کے طور پر شامل کرنے کے لیے، یقینی بنائیں کہ ایپ انسٹال ہے"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• کم از کم ایک آلہ دستیاب ہے"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"نوٹ لینے والے شارٹ کٹ کا استعمال کرنے کے لیے ڈیفالٹ نوٹس ایپ منتخب کریں"</string>
@@ -1178,8 +1180,8 @@
<string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"رسائی کا نظم کریں"</string>
<string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"فون کال کے زیر استعمال"</string>
<string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"فون کال میں حال ہی میں استعمال کیا گیا"</string>
- <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے زیر استعمال"</string>
- <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے ذریعے حال ہی میں استعمال کیا گیا"</string>
+ <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے زیر استعمال"</string>
+ <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"حال ہی میں <xliff:g id="APP_NAME">%1$s</xliff:g> نے استعمال کیا"</string>
<string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) کے زیر استعمال"</string>
<string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) کے ذریعے حال ہی میں استعمال کیا گیا"</string>
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) کے زیر استعمال"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 65f5653..b7defbb 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Ish ilovalari"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pauzada"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Tungi rejim"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Kunbotarda yoqish"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Quyosh chiqqunicha"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Kattalashtirish sozlamalarini ochish"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Kattalashtirish sozlamalarini yopish"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Oʻlchamini oʻzgartirish uchun burchakni torting"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonal aylantirishga ruxsat berish"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Oʻlchamini oʻzgartirish"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ochish: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ilovasini yorliq sifatida qoʻshish uchun ilova oʻrnatilganiga ishonch hosil qiling"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ilovasini yorliq sifatida qoʻshish uchun kamida bitta karta kiritilganiga ishonch hosil qiling"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR kod skanerini yorliq sifatida qoʻshish uchun kamera ilovasi oʻrnatilganiga ishonch hosil qiling"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ilovasini yorliq sifatida qoʻshish uchun ilova oʻrnatilganiga ishonch hosil qiling"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Kamida bitta qurilma mavjud"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Qayd yozish yorligʻidan foydalanish uchun birlamchi qayd ilovasini tanlang"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8be1dd5..2d49b02 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Giới hạn <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Ứng dụng công việc"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Đã tạm dừng"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ánh sáng đêm"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Bật khi trời tối"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Cho đến khi trời sáng"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Mở chế độ cài đặt phóng to"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Đóng bảng cài đặt tính năng phóng to"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Kéo góc để thay đổi kích thước"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Cho phép cuộn chéo"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Đổi kích thước"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Mở <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Để tạo lối tắt cho ứng dụng Wallet, hãy đảm bảo bạn đã cài đặt ứng dụng đó"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Để tạo lối tắt cho ứng dụng Wallet, hãy đảm bảo bạn đã thêm ít nhất một thẻ"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Để tạo lối tắt cho Trình quét mã QR, hãy đảm bảo rằng bạn đã cài đặt một ứng dụng máy ảnh"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Để tạo lối tắt cho ứng dụng Home, hãy đảm bảo bạn đã cài đặt ứng dụng đó"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Có ít nhất một thiết bị đang hoạt động"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Chọn một ứng dụng ghi chú mặc định để dùng lối tắt ghi chú"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 299ebf9..8d2b89b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"上限为<xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"工作应用"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"已暂停"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"护眼模式"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"在日落时开启"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"在日出时关闭"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"打开放大功能设置"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"关闭放大设置"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"退出修改模式"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖动一角即可调整大小"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允许沿对角线滚动"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"调整大小"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"打开<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"若要将 Google 钱包应用添加为快捷方式,请确保已安装该应用"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"若要将 Google 钱包应用添加为快捷方式,请确保至少已添加一张银行卡"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"若要将二维码扫描器添加为快捷方式,请确保已安装相机应用"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"若要将 Home 应用添加为快捷方式,请确保已安装该应用"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 至少有一台设备可用"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"选择默认记事应用即可使用记事快捷方式"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index fb40f32..9e408f2 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"工作應用程式"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"已暫停"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜間模式"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"在日落時開啟"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"在日出時關閉"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分螢幕畫面"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"開啟放大設定"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"關閉放大設定"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"結束編輯模式"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許斜角捲動"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"調整大小"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"如要將「錢包」應用程式新增為捷徑,請確認已安裝該應用程式"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"如要將「錢包」應用程式新增為捷徑,請確認已新增至少一張付款卡"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"如要將 QR 碼掃瞄器新增為捷徑,請確認已安裝相機應用程式"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"如要將 Home 應用程式新增為捷徑,請確認已安裝該應用程式"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 至少一部裝置可用"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"選取預設的筆記應用程式,即可使用筆記捷徑"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4750b5b..5831ac5 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"工作應用程式"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"已暫停"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜燈"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"於日落時開啟"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"於日出時關閉"</string>
@@ -864,6 +865,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大局部螢幕畫面"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"開啟放大功能設定"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"關閉放大設定"</string>
+ <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"結束編輯模式"</string>
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許沿對角線捲動"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"調整大小"</string>
@@ -1133,7 +1135,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"如要將錢包應用程式新增為捷徑,請確認已安裝該應用程式"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"如要將錢包應用程式新增為捷徑,請確認已新增至少一張卡片"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"如要將 QR code 掃描器新增為捷徑,請確認已安裝相機應用程式"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"如要將 Google Home 應用程式新增為捷徑,請確認已安裝該應用程式"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 至少要有一部可用裝置"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"選取預設的記事應用程式,即可使用筆記捷徑"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e22d1d7..5013f8d 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -295,6 +295,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> umkhawulo"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Ama-app omsebenzi"</string>
+ <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Kumisiwe"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ukukhanya kwasebusuku"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Kuvulwe ekushoneni kwelanga"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Kuze kube sekuphumeni kwelanga"</string>
@@ -864,6 +865,8 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Vula amasethingi okukhuliswa"</string>
<string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Vala amasethingi okukhuliswa"</string>
+ <!-- no translation found for magnification_exit_edit_mode_click_label (1664818325144887117) -->
+ <skip />
<string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Hudula ikhona ukuze usayize kabusha"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Vumela ukuskrola oku-diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Shintsha usayizi"</string>
@@ -1133,7 +1136,6 @@
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Vula i-<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ukuze ungeze i-app ye-Wallet njengesinqamuleli, qinisekisa ukuthi i-app ifakiwe"</string>
<string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ukuze ungeze i-app ye-Wallet njengesinqamuleli, qinisekisa ukuthi okungenani ikhadi elilodwa lingeziwe"</string>
- <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ukuze ungeze Iskena sekhodi ye-QR njengesinqamuleli, qinisekisa ukuthi i-app yekhamera ifakiwe"</string>
<string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ukuze ungeze i-App yasekhaya njengesinqamuleli, qinisekisa ukuthi i-app ifakiwe"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Okungenani idivayisi eyodwa iyatholakala"</string>
<string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Khetha i-app yamanothi azenzakalelayo ukuze usebenzise isinqamuleli sokubhala amanothi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6164f29f..4aad6e7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -917,4 +917,7 @@
"$packageName" part that will be replaced by the code with the package name of the target app.
-->
<string name="config_appStoreAppLinkTemplate" translatable="false"></string>
+
+ <!-- Flag controlling whether visual query attention detection has been enabled. -->
+ <bool name="config_enableVisualQueryAttentionDetection">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 55978e6..3ada7c2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -496,9 +496,10 @@
<dimen name="large_screen_shade_header_min_height">@dimen/qs_header_row_min_height</dimen>
<dimen name="large_screen_shade_header_left_padding">@dimen/qs_horizontal_margin</dimen>
<dimen name="shade_header_system_icons_height">@dimen/large_screen_shade_header_min_height</dimen>
- <dimen name="shade_header_system_icons_height_large_screen">32dp</dimen>
<dimen name="shade_header_system_icons_padding_start">0dp</dimen>
<dimen name="shade_header_system_icons_padding_end">0dp</dimen>
+ <dimen name="shade_header_system_icons_padding_top">0dp</dimen>
+ <dimen name="shade_header_system_icons_padding_bottom">0dp</dimen>
<!-- The top margin of the panel that holds the list of notifications.
On phones it's always 0dp but it's overridden in Car UI
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 261b08d..0d45422 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -39,7 +39,7 @@
<bool name="flag_battery_shield_icon">false</bool>
<!-- Whether face auth will immediately stop when the display state is OFF -->
- <bool name="flag_stop_face_auth_on_display_off">false</bool>
+ <bool name="flag_stop_face_auth_on_display_off">true</bool>
<!-- Whether we want to stop pulsing while running the face scanning animation -->
<bool name="flag_stop_pulsing_face_scanning_animation">true</bool>
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index 2ec6180..fe61c46 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -56,7 +56,7 @@
<Constraint android:id="@+id/shade_header_system_icons">
<Layout
android:layout_width="wrap_content"
- android:layout_height="@dimen/shade_header_system_icons_height_large_screen"
+ android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/privacy_container"
app:layout_constraintTop_toTopOf="parent"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index c844db7..77f6d03 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -28,8 +28,6 @@
import java.lang.annotation.RetentionPolicy;
public final class InteractionJankMonitorWrapper {
- private static final String TAG = "JankMonitorWrapper";
-
// Launcher journeys.
public static final int CUJ_APP_LAUNCH_FROM_RECENTS =
InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS;
@@ -37,6 +35,8 @@
InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON;
public static final int CUJ_APP_CLOSE_TO_HOME =
InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_HOME;
+ public static final int CUJ_APP_CLOSE_TO_HOME_FALLBACK =
+ InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
public static final int CUJ_APP_CLOSE_TO_PIP =
InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP;
public static final int CUJ_QUICK_SWITCH =
@@ -68,6 +68,7 @@
CUJ_APP_LAUNCH_FROM_RECENTS,
CUJ_APP_LAUNCH_FROM_ICON,
CUJ_APP_CLOSE_TO_HOME,
+ CUJ_APP_CLOSE_TO_HOME_FALLBACK,
CUJ_APP_CLOSE_TO_PIP,
CUJ_QUICK_SWITCH,
CUJ_APP_LAUNCH_FROM_WIDGET,
diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
new file mode 100644
index 0000000..899cad89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.app.Presentation
+import android.content.Context
+import android.graphics.Color
+import android.os.Bundle
+import android.view.Display
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import com.android.keyguard.dagger.KeyguardStatusViewComponent
+import com.android.systemui.R
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/** [Presentation] shown in connected displays while on keyguard. */
+class ConnectedDisplayKeyguardPresentation
+@AssistedInject
+constructor(
+ @Assisted display: Display,
+ context: Context,
+ private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
+) :
+ Presentation(
+ context,
+ display,
+ R.style.Theme_SystemUI_KeyguardPresentation,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
+ ) {
+
+ private lateinit var keyguardStatusViewController: KeyguardStatusViewController
+ private lateinit var clock: KeyguardStatusView
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(
+ LayoutInflater.from(context)
+ .inflate(R.layout.keyguard_clock_presentation, /* root= */ null)
+ )
+ val window = window ?: error("no window available.")
+
+ // Logic to make the lock screen fullscreen
+ window.decorView.systemUiVisibility =
+ (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
+ window.attributes.fitInsetsTypes = 0
+ window.isNavigationBarContrastEnforced = false
+ window.navigationBarColor = Color.TRANSPARENT
+
+ clock = findViewById(R.id.clock)
+ keyguardStatusViewController =
+ keyguardStatusViewComponentFactory.build(clock).keyguardStatusViewController.apply {
+ setDisplayedOnSecondaryDisplay()
+ init()
+ }
+ }
+
+ /** [ConnectedDisplayKeyguardPresentation] factory. */
+ @AssistedFactory
+ interface Factory {
+ /** Creates a new [Presentation] for the given [display]. */
+ fun create(
+ display: Display,
+ ): ConnectedDisplayKeyguardPresentation
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index b81e081..e3f9de1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -102,6 +102,12 @@
super.onViewAttached();
mView.setKeyDownListener(mKeyDownListener);
mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback);
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (shouldLockout(deadline)) {
+ handleAttemptLockout(deadline);
+ }
}
@Override
@@ -278,12 +284,6 @@
@Override
public void onResume(int reason) {
mResumed = true;
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (shouldLockout(deadline)) {
- handleAttemptLockout(deadline);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index b4f1956..5d0e8f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,10 +1,5 @@
package com.android.keyguard;
-import static android.view.View.ALPHA;
-import static android.view.View.SCALE_X;
-import static android.view.View.SCALE_Y;
-import static android.view.View.TRANSLATION_Y;
-
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_X_CLOCK_DESIGN;
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_DESIGN;
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_SIZE;
@@ -44,6 +39,7 @@
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
+ public static final String MISSING_CLOCK_ID = "CLOCK_MISSING";
private static final long CLOCK_OUT_MILLIS = 133;
private static final long CLOCK_IN_MILLIS = 167;
@@ -145,6 +141,13 @@
updateStatusArea(/* animate= */false);
}
+ /** Sets whether the large clock is being shown on a connected display. */
+ public void setLargeClockOnSecondaryDisplay(boolean onSecondaryDisplay) {
+ if (mClock != null) {
+ mClock.getLargeClock().getEvents().onSecondaryDisplayChanged(onSecondaryDisplay);
+ }
+ }
+
/**
* Enable or disable split shade specific positioning
*/
@@ -190,6 +193,14 @@
return mLogBuffer;
}
+ /** Returns the id of the currently rendering clock */
+ public String getClockId() {
+ if (mClock == null) {
+ return MISSING_CLOCK_ID;
+ }
+ return mClock.getConfig().getId();
+ }
+
void setClock(ClockController clock, int statusBarState) {
mClock = clock;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index a9531cf..8108076 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -104,6 +104,7 @@
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private boolean mShownOnSecondaryDisplay = false;
private boolean mOnlyClock = false;
private boolean mIsActiveDreamLockscreenHosted = false;
private FeatureFlags mFeatureFlags;
@@ -185,8 +186,18 @@
}
/**
- * Mostly used for alternate displays, limit the information shown
+ * When set, limits the information shown in an external display.
*/
+ public void setShownOnSecondaryDisplay(boolean shownOnSecondaryDisplay) {
+ mShownOnSecondaryDisplay = shownOnSecondaryDisplay;
+ }
+
+ /**
+ * Mostly used for alternate displays, limit the information shown
+ *
+ * @deprecated use {@link KeyguardClockSwitchController#setShownOnSecondaryDisplay}
+ */
+ @Deprecated
public void setOnlyClock(boolean onlyClock) {
mOnlyClock = onlyClock;
}
@@ -221,6 +232,15 @@
}
}
+ private void hideSliceViewAndNotificationIconContainer() {
+ View ksv = mView.findViewById(R.id.keyguard_slice_view);
+ ksv.setVisibility(View.GONE);
+
+ View nic = mView.findViewById(
+ R.id.left_aligned_notification_icon_container);
+ nic.setVisibility(View.GONE);
+ }
+
@Override
protected void onViewAttached() {
mClockRegistry.registerClockChangeListener(mClockChangedListener);
@@ -233,13 +253,15 @@
mKeyguardDateWeatherViewInvisibility =
mView.getResources().getInteger(R.integer.keyguard_date_weather_view_invisibility);
- if (mOnlyClock) {
- View ksv = mView.findViewById(R.id.keyguard_slice_view);
- ksv.setVisibility(View.GONE);
+ if (mShownOnSecondaryDisplay) {
+ mView.setLargeClockOnSecondaryDisplay(true);
+ displayClock(LARGE, /* animate= */ false);
+ hideSliceViewAndNotificationIconContainer();
+ return;
+ }
- View nic = mView.findViewById(
- R.id.left_aligned_notification_icon_container);
- nic.setVisibility(View.GONE);
+ if (mOnlyClock) {
+ hideSliceViewAndNotificationIconContainer();
return;
}
updateAodIcons();
@@ -292,6 +314,7 @@
setClock(null);
mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver);
+ mSecureSettings.unregisterContentObserver(mShowWeatherObserver);
mKeyguardUnlockAnimationController.removeKeyguardUnlockAnimationListener(
mKeyguardUnlockAnimationListener);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 9f21a31..1c5a575 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -43,16 +43,19 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import dagger.Lazy;
+
import java.util.concurrent.Executor;
import javax.inject.Inject;
-import dagger.Lazy;
@SysUISingleton
public class KeyguardDisplayManager {
@@ -64,6 +67,9 @@
private final DisplayTracker mDisplayTracker;
private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ private final ConnectedDisplayKeyguardPresentation.Factory
+ mConnectedDisplayKeyguardPresentationFactory;
+ private final FeatureFlags mFeatureFlags;
private final Context mContext;
private boolean mShowing;
@@ -105,7 +111,10 @@
@Main Executor mainExecutor,
@UiBackground Executor uiBgExecutor,
DeviceStateHelper deviceStateHelper,
- KeyguardStateController keyguardStateController) {
+ KeyguardStateController keyguardStateController,
+ ConnectedDisplayKeyguardPresentation.Factory
+ connectedDisplayKeyguardPresentationFactory,
+ FeatureFlags featureFlags) {
mContext = context;
mNavigationBarControllerLazy = navigationBarControllerLazy;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
@@ -115,6 +124,8 @@
mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
mDeviceStateHelper = deviceStateHelper;
mKeyguardStateController = keyguardStateController;
+ mConnectedDisplayKeyguardPresentationFactory = connectedDisplayKeyguardPresentationFactory;
+ mFeatureFlags = featureFlags;
}
private boolean isKeyguardShowable(Display display) {
@@ -185,8 +196,12 @@
return false;
}
- KeyguardPresentation createPresentation(Display display) {
- return new KeyguardPresentation(mContext, display, mKeyguardStatusViewComponentFactory);
+ Presentation createPresentation(Display display) {
+ if (mFeatureFlags.isEnabled(Flags.ENABLE_CLOCK_KEYGUARD_PRESENTATION)) {
+ return mConnectedDisplayKeyguardPresentationFactory.create(display);
+ } else {
+ return new KeyguardPresentation(mContext, display, mKeyguardStatusViewComponentFactory);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 20e4656..42dbc48 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -30,13 +30,13 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.ui.BouncerMessageView;
+import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.bouncer.ui.BouncerMessageView;
-import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder;
import com.android.systemui.log.BouncerLogger;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.ViewController;
@@ -95,6 +95,12 @@
@CallSuper
protected void onViewAttached() {
updateMessageAreaVisibility();
+ if (TextUtils.isEmpty(mMessageAreaController.getMessage())
+ && getInitialMessageResId() != 0) {
+ mMessageAreaController.setMessage(
+ mView.getResources().getString(getInitialMessageResId()),
+ /* animate= */ false);
+ }
}
private void updateMessageAreaVisibility() {
@@ -147,12 +153,6 @@
}
public void startAppearAnimation() {
- if (TextUtils.isEmpty(mMessageAreaController.getMessage())
- && getInitialMessageResId() != 0) {
- mMessageAreaController.setMessage(
- mView.getResources().getString(getInitialMessageResId()),
- /* animate= */ false);
- }
mView.startAppearAnimation();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 49f788c..a30b447 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -238,6 +238,12 @@
}
mView.onDevicePostureChanged(mPostureController.getDevicePosture());
mPostureController.addCallback(mPostureCallback);
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (deadline != 0) {
+ handleAttemptLockout(deadline);
+ }
}
@Override
@@ -268,12 +274,6 @@
@Override
public void onResume(int reason) {
super.onResume(reason);
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (deadline != 0) {
- handleAttemptLockout(deadline);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index b3e08c0..574a059 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -79,6 +79,10 @@
mPasswordEntry.setUserActivityListener(this::onUserInput);
mView.onDevicePostureChanged(mPostureController.getDevicePosture());
mPostureController.addCallback(mPostureCallback);
+ if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) {
+ mPasswordEntry.setUsePinShapes(true);
+ updateAutoConfirmationState();
+ }
}
protected void onUserInput() {
@@ -100,10 +104,6 @@
@Override
public void startAppearAnimation() {
- if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) {
- mPasswordEntry.setUsePinShapes(true);
- updateAutoConfirmationState();
- }
super.startAppearAnimation();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d9a1dc6..9f3908a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -27,6 +27,7 @@
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES;
import android.app.ActivityManager;
@@ -84,6 +85,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.user.domain.interactor.UserInteractor;
@@ -146,8 +148,19 @@
private int mLastOrientation;
private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
+ private int mCurrentUser = UserHandle.USER_NULL;
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
- () -> showPrimarySecurityScreen(false);
+ new UserSwitcherController.UserSwitchCallback() {
+ @Override
+ public void onUserSwitched() {
+ if (mCurrentUser == KeyguardUpdateMonitor.getCurrentUser()) {
+ return;
+ }
+ mCurrentUser = KeyguardUpdateMonitor.getCurrentUser();
+ showPrimarySecurityScreen(false);
+ reinflateViewFlipper((l) -> {});
+ }
+ };
@VisibleForTesting
final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
@@ -343,7 +356,6 @@
@Override
public void onThemeChanged() {
reloadColors();
- reset();
}
@Override
@@ -359,8 +371,12 @@
@Override
public void onOrientationChanged(int orientation) {
- KeyguardSecurityContainerController.this
+ if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
+ // TODO(b/295603468)
+ // Fix reinflation of views when flag is enabled.
+ KeyguardSecurityContainerController.this
.onDensityOrFontScaleOrOrientationChanged();
+ }
}
};
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
@@ -401,6 +417,7 @@
private final UserInteractor mUserInteractor;
private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
private final Provider<JavaAdapter> mJavaAdapter;
+ private final DeviceProvisionedController mDeviceProvisionedController;
@Nullable private Job mSceneTransitionCollectionJob;
@Inject
@@ -429,6 +446,7 @@
BouncerMessageInteractor bouncerMessageInteractor,
Provider<JavaAdapter> javaAdapter,
UserInteractor userInteractor,
+ DeviceProvisionedController deviceProvisionedController,
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
KeyguardTransitionInteractor keyguardTransitionInteractor,
Provider<AuthenticationInteractor> authenticationInteractor
@@ -463,6 +481,7 @@
mAuthenticationInteractor = authenticationInteractor;
mJavaAdapter = javaAdapter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override
@@ -847,9 +866,11 @@
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser());
- if (securityMode == SecurityMode.None || isLockscreenDisabled) {
- finish = isLockscreenDisabled;
+ KeyguardUpdateMonitor.getCurrentUser())
+ || !mDeviceProvisionedController.isUserSetup(targetUserId);
+
+ if (securityMode == SecurityMode.None && isLockscreenDisabled) {
+ finish = true;
eventSubtype = BOUNCER_DISMISS_SIM;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
} else {
@@ -1164,7 +1185,7 @@
}
private void reloadColors() {
- reinflateViewFlipper(controller -> mView.reloadColors());
+ mView.reloadColors();
}
/** Handles density or font scale changes. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 757022d..c314586 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -187,6 +187,11 @@
mConfigurationController.removeCallback(mConfigurationListener);
}
+ /** Sets the StatusView as shown on an external display. */
+ public void setDisplayedOnSecondaryDisplay() {
+ mKeyguardClockSwitchController.setShownOnSecondaryDisplay(true);
+ }
+
/**
* Called in notificationPanelViewController to avoid leak
*/
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 2b83e6b..590056f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -23,6 +23,8 @@
import android.util.Log;
import com.android.internal.app.AssistUtils;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.internal.app.IVisualQueryRecognitionStatusListener;
import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -39,10 +41,13 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.settings.SecureSettings;
-import javax.inject.Inject;
-
import dagger.Lazy;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
/**
* Class to manage everything related to assist in SystemUI.
*/
@@ -78,6 +83,18 @@
void hide();
}
+ /**
+ * An interface for a listener that receives notification that visual query attention has
+ * either been gained or lost.
+ */
+ public interface VisualQueryAttentionListener {
+ /** Called when visual query attention has been gained. */
+ void onAttentionGained();
+
+ /** Called when visual query attention has been lost. */
+ void onAttentionLost();
+ }
+
private static final String TAG = "AssistManager";
// Note that VERBOSE logging may leak PII (e.g. transcription contents).
@@ -127,6 +144,23 @@
private final SecureSettings mSecureSettings;
private final DeviceProvisionedController mDeviceProvisionedController;
+
+ private final List<VisualQueryAttentionListener> mVisualQueryAttentionListeners =
+ new ArrayList<>();
+
+ private final IVisualQueryDetectionAttentionListener mVisualQueryDetectionAttentionListener =
+ new IVisualQueryDetectionAttentionListener.Stub() {
+ @Override
+ public void onAttentionGained() {
+ mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionGained);
+ }
+
+ @Override
+ public void onAttentionLost() {
+ mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionLost);
+ }
+ };
+
private final CommandQueue mCommandQueue;
protected final AssistUtils mAssistUtils;
@@ -157,6 +191,7 @@
mSecureSettings = secureSettings;
registerVoiceInteractionSessionListener();
+ registerVisualQueryRecognitionStatusListener();
mUiController = defaultUiController;
@@ -266,6 +301,24 @@
mAssistUtils.hideCurrentSession();
}
+ /**
+ * Add the given {@link VisualQueryAttentionListener} to the list of listeners awaiting
+ * notification of gaining/losing visual query attention.
+ */
+ public void addVisualQueryAttentionListener(VisualQueryAttentionListener listener) {
+ if (!mVisualQueryAttentionListeners.contains(listener)) {
+ mVisualQueryAttentionListeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the given {@link VisualQueryAttentionListener} from the list of listeners awaiting
+ * notification of gaining/losing visual query attention.
+ */
+ public void removeVisualQueryAttentionListener(VisualQueryAttentionListener listener) {
+ mVisualQueryAttentionListeners.remove(listener);
+ }
+
private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
boolean isService) {
if (isService) {
@@ -326,6 +379,27 @@
null, null);
}
+ private void registerVisualQueryRecognitionStatusListener() {
+ if (!mContext.getResources()
+ .getBoolean(R.bool.config_enableVisualQueryAttentionDetection)) {
+ return;
+ }
+
+ mAssistUtils.subscribeVisualQueryRecognitionStatus(
+ new IVisualQueryRecognitionStatusListener.Stub() {
+ @Override
+ public void onStartPerceiving() {
+ mAssistUtils.enableVisualQueryDetection(
+ mVisualQueryDetectionAttentionListener);
+ }
+
+ @Override
+ public void onStopPerceiving() {
+ mAssistUtils.disableVisualQueryDetection();
+ }
+ });
+ }
+
public void launchVoiceAssistFromKeyguard() {
mAssistUtils.launchVoiceAssistFromKeyguard();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
index 1817ea9..64bf688 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
@@ -36,7 +36,6 @@
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R.string.bouncer_face_not_recognized
import com.android.systemui.R.string.keyguard_enter_password
import com.android.systemui.R.string.keyguard_enter_pattern
@@ -80,13 +79,14 @@
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import javax.inject.Inject
@SysUISingleton
class BouncerMessageFactory
@Inject
constructor(
- private val updateMonitor: KeyguardUpdateMonitor,
+ private val biometricSettingsRepository: BiometricSettingsRepository,
private val securityModel: KeyguardSecurityModel,
) {
@@ -99,7 +99,7 @@
getBouncerMessage(
reason,
securityModel.getSecurityMode(userId),
- updateMonitor.isUnlockingWithFingerprintAllowed
+ biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value
)
return pair?.let {
BouncerMessageModel(
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
index 6fb0d4c..97c1bdb 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
@@ -123,20 +123,11 @@
fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
) : BouncerMessageRepository {
- private val isFaceEnrolledAndEnabled =
- and(
- biometricSettingsRepository.isFaceAuthenticationEnabled,
- biometricSettingsRepository.isFaceEnrolled
- )
-
- private val isFingerprintEnrolledAndEnabled =
- and(
- biometricSettingsRepository.isFingerprintEnabledByDevicePolicy,
- biometricSettingsRepository.isFingerprintEnrolled
- )
-
private val isAnyBiometricsEnabledAndEnrolled =
- or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled)
+ or(
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
+ biometricSettingsRepository.isFingerprintEnrolledAndEnabled,
+ )
private val wasRebootedForMainlineUpdate
get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
@@ -335,8 +326,5 @@
}
}
-private fun and(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
- flow.combine(anotherFlow) { a, b -> a && b }
-
private fun or(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
flow.combine(anotherFlow) { a, b -> a || b }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 98ae54b..9a7fec1 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -83,9 +83,7 @@
fun canShowAlternateBouncerForFingerprint(): Boolean {
return bouncerRepository.alternateBouncerUIAvailable.value &&
- biometricSettingsRepository.isFingerprintEnrolled.value &&
- biometricSettingsRepository.isStrongBiometricAllowed.value &&
- biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
+ biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value &&
!keyguardUpdateMonitor.isFingerprintLockedOut &&
!keyguardStateController.isUnlocked &&
!statusBarStateController.isDozing
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
index 566a74a..d58fab4 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -27,7 +27,8 @@
import com.android.systemui.R;
class IntentCreator {
- private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
+ private static final String EXTRA_EDIT_SOURCE = "edit_source";
+ private static final String EDIT_SOURCE_CLIPBOARD = "clipboard";
private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
static Intent getTextEditorIntent(Context context) {
@@ -74,7 +75,7 @@
editIntent.setDataAndType(uri, "image/*");
editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- editIntent.putExtra(EXTRA_EDIT_SOURCE_CLIPBOARD, true);
+ editIntent.putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD);
return editIntent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index 8029ba8..534832c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -54,9 +54,10 @@
/**
* When a ToggleRange control is interacting with, a drag event is sent.
*
+ * @param cvh [ControlViewHolder] for the control
* @param isEdge did the drag event reach a control edge
*/
- fun drag(isEdge: Boolean)
+ fun drag(cvh: ControlViewHolder, isEdge: Boolean)
/**
* Send a request to update the value of a device using the [FloatAction].
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index a7e9efd8..00d95c0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -37,6 +37,8 @@
import com.android.systemui.controls.settings.ControlsSettingsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -57,6 +59,7 @@
private val controlsMetricsLogger: ControlsMetricsLogger,
private val vibrator: VibratorHelper,
private val controlsSettingsRepository: ControlsSettingsRepository,
+ private val featureFlags: FeatureFlags,
) : ControlActionCoordinator {
private var dialog: Dialog? = null
private var pendingAction: Action? = null
@@ -119,11 +122,17 @@
)
}
- override fun drag(isEdge: Boolean) {
- if (isEdge) {
- vibrate(Vibrations.rangeEdgeEffect)
+ override fun drag(cvh: ControlViewHolder, isEdge: Boolean) {
+ if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ val constant =
+ if (isEdge)
+ HapticFeedbackConstants.SEGMENT_TICK
+ else
+ HapticFeedbackConstants.SEGMENT_FREQUENT_TICK
+ vibrator.performHapticFeedback(cvh.layout, constant)
} else {
- vibrate(Vibrations.rangeMiddleEffect)
+ val effect = if (isEdge) Vibrations.rangeEdgeEffect else Vibrations.rangeMiddleEffect
+ vibrate(effect)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index b2c95a6..0d570d2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -235,7 +235,7 @@
if (isDragging) {
val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
if (clipLayer.level != newLevel) {
- cvh.controlActionCoordinator.drag(isEdge)
+ cvh.controlActionCoordinator.drag(cvh, isEdge)
clipLayer.level = newLevel
}
} else if (newLevel != clipLayer.level) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index d9665c5b5..484be9c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -53,6 +53,7 @@
import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.statusbar.phone.LockscreenWallpaper
import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener
import com.android.systemui.stylus.StylusUsiPowerStartable
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.theme.ThemeOverlayController
@@ -331,4 +332,11 @@
@IntoMap
@ClassKey(ScrimController::class)
abstract fun bindScrimController(impl: ScrimController): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(StatusBarHeadsUpChangeListener::class)
+ abstract fun bindStatusBarHeadsUpChangeListener(
+ impl: StatusBarHeadsUpChangeListener
+ ): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f73a602..64c4eec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -107,6 +107,7 @@
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LetterboxModule;
+import com.android.systemui.statusbar.phone.NotificationIconAreaControllerModule;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -184,6 +185,7 @@
MediaProjectionModule.class,
MediaProjectionTaskSwitcherModule.class,
MotionToolModule.class,
+ NotificationIconAreaControllerModule.class,
PeopleHubModule.class,
PeopleModule.class,
PluginModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
index c889ac2..4dd97d5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
@@ -16,10 +16,9 @@
package com.android.systemui.dreams.conditions;
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
import com.android.systemui.dagger.qualifiers.Application;
-import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
@@ -30,12 +29,10 @@
* {@link AssistantAttentionCondition} provides a signal when assistant has the user's attention.
*/
public class AssistantAttentionCondition extends Condition {
- private final DreamOverlayStateController mDreamOverlayStateController;
- private final AssistUtils mAssistUtils;
- private boolean mEnabled;
+ private final AssistManager mAssistManager;
- private final IVisualQueryDetectionAttentionListener mVisualQueryDetectionAttentionListener =
- new IVisualQueryDetectionAttentionListener.Stub() {
+ private final VisualQueryAttentionListener mVisualQueryAttentionListener =
+ new VisualQueryAttentionListener() {
@Override
public void onAttentionGained() {
updateCondition(true);
@@ -47,59 +44,26 @@
}
};
- private final DreamOverlayStateController.Callback mCallback =
- new DreamOverlayStateController.Callback() {
- @Override
- public void onStateChanged() {
- if (mDreamOverlayStateController.isDreamOverlayStatusBarVisible()) {
- enableVisualQueryDetection();
- } else {
- disableVisualQueryDetection();
- }
- }
- };
-
@Inject
public AssistantAttentionCondition(
@Application CoroutineScope scope,
- DreamOverlayStateController dreamOverlayStateController,
- AssistUtils assistUtils) {
+ AssistManager assistManager) {
super(scope);
- mDreamOverlayStateController = dreamOverlayStateController;
- mAssistUtils = assistUtils;
+ mAssistManager = assistManager;
}
@Override
protected void start() {
- mDreamOverlayStateController.addCallback(mCallback);
+ mAssistManager.addVisualQueryAttentionListener(mVisualQueryAttentionListener);
}
@Override
protected void stop() {
- disableVisualQueryDetection();
- mDreamOverlayStateController.removeCallback(mCallback);
+ mAssistManager.removeVisualQueryAttentionListener(mVisualQueryAttentionListener);
}
@Override
protected int getStartStrategy() {
return START_EAGERLY;
}
-
- private void enableVisualQueryDetection() {
- if (mEnabled) {
- return;
- }
- mEnabled = true;
- mAssistUtils.enableVisualQueryDetection(mVisualQueryDetectionAttentionListener);
- }
-
- private void disableVisualQueryDetection() {
- if (!mEnabled) {
- return;
- }
- mEnabled = false;
- mAssistUtils.disableVisualQueryDetection();
- // Make sure the condition is set to false as well.
- updateCondition(false);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5b56223..6d68eef 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -115,7 +115,7 @@
// TODO(b/292213543): Tracking Bug
@JvmField
val NOTIFICATION_GROUP_EXPANSION_CHANGE =
- unreleasedFlag("notification_group_expansion_change", teamfood = false)
+ unreleasedFlag("notification_group_expansion_change", teamfood = true)
// 200 - keyguard/lockscreen
// ** Flag retired **
@@ -195,7 +195,7 @@
// TODO(b/294110497): Tracking Bug
@JvmField
val ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS =
- unreleasedFlag("enable_wallet_contextual_loyalty_cards", teamfood = true)
+ releasedFlag("enable_wallet_contextual_loyalty_cards")
// TODO(b/242908637): Tracking Bug
@JvmField val WALLPAPER_FULLSCREEN_PREVIEW = releasedFlag("wallpaper_fullscreen_preview")
@@ -386,8 +386,7 @@
@JvmField val NEW_BLUETOOTH_REPOSITORY = releasedFlag("new_bluetooth_repository")
// TODO(b/292533677): Tracking Bug
- val WIFI_TRACKER_LIB_FOR_WIFI_ICON =
- unreleasedFlag("wifi_tracker_lib_for_wifi_icon", teamfood = true)
+ val WIFI_TRACKER_LIB_FOR_WIFI_ICON = releasedFlag("wifi_tracker_lib_for_wifi_icon")
// TODO(b/293863612): Tracking Bug
@JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
@@ -399,6 +398,10 @@
// TODO(b/294588085): Tracking Bug
val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks")
+ // TODO(b/290676905): Tracking Bug
+ val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS =
+ unreleasedFlag("new_shade_carrier_group_mobile_icons")
+
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag("ongoing_call_status_bar_chip")
@@ -503,21 +506,6 @@
val WM_CAPTION_ON_SHELL =
sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
- @Keep
- @JvmField
- val ENABLE_FLING_TO_DISMISS_BUBBLE =
- sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_bubble", default = true)
-
- @Keep
- @JvmField
- val ENABLE_FLING_TO_DISMISS_PIP =
- sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_pip", default = true)
-
- @Keep
- @JvmField
- val ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
- sysPropBooleanFlag("persist.wm.debug.enable_pip_keep_clear_algorithm", default = true)
-
// TODO(b/256873975): Tracking Bug
@JvmField
@Keep
@@ -539,19 +527,6 @@
teamfood = false
)
- // TODO(b/198643358): Tracking bug
- @Keep
- @JvmField
- val ENABLE_PIP_SIZE_LARGE_SCREEN =
- sysPropBooleanFlag("persist.wm.debug.enable_pip_size_large_screen", default = true)
-
- // TODO(b/265998256): Tracking bug
- @Keep
- @JvmField
- val ENABLE_PIP_APP_ICON_OVERLAY =
- sysPropBooleanFlag("persist.wm.debug.enable_pip_app_icon_overlay", default = true)
-
-
// TODO(b/293252410) : Tracking Bug
@JvmField
val LOCKSCREEN_ENABLE_LANDSCAPE =
@@ -635,6 +610,10 @@
// TODO(b/251205791): Tracking Bug
@JvmField val SCREENSHOT_APP_CLIPS = releasedFlag("screenshot_app_clips")
+ /** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */
+ @JvmField
+ val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot")
+
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
val QUICK_TAP_IN_PCC = releasedFlag("quick_tap_in_pcc")
@@ -776,6 +755,10 @@
@JvmField
val ONE_WAY_HAPTICS_API_MIGRATION = unreleasedFlag("oneway_haptics_api_migration")
+ /** TODO(b/296223317): Enables the new keyguard presentation containing a clock. */
+ @JvmField
+ val ENABLE_CLOCK_KEYGUARD_PRESENTATION = unreleasedFlag("enable_clock_keyguard_presentation")
+
/** Enable the Compose implementation of the PeopleSpaceActivity. */
@JvmField
val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space")
@@ -787,4 +770,8 @@
/** Enable the share wifi button in Quick Settings internet dialog. */
@JvmField
val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button")
+
+ /** Enable haptic slider component in the brightness slider */
+ @JvmField
+ val HAPTIC_BRIGHTNESS_SLIDER = unreleasedFlag("haptic_brightness_slider")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
new file mode 100644
index 0000000..3f2f67d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.keyevent.domain.interactor
+
+import android.view.KeyEvent
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
+import javax.inject.Inject
+
+/**
+ * Sends key events to the appropriate interactors and then acts upon key events that haven't
+ * already been handled but should be handled by SystemUI.
+ */
+@SysUISingleton
+class KeyEventInteractor
+@Inject
+constructor(
+ private val backActionInteractor: BackActionInteractor,
+ private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor,
+) {
+ fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) {
+ return true
+ }
+
+ when (event.keyCode) {
+ KeyEvent.KEYCODE_BACK -> {
+ if (event.handleAction()) {
+ backActionInteractor.onBackRequested()
+ }
+ return true
+ }
+ }
+ return false
+ }
+
+ fun interceptMediaKey(event: KeyEvent): Boolean {
+ return keyguardKeyEventInteractor.interceptMediaKey(event)
+ }
+
+ fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
+ return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event)
+ }
+
+ companion object {
+ // Most actions shouldn't be handled on the down event and instead handled on subsequent
+ // key events like ACTION_UP.
+ fun KeyEvent.handleAction(): Boolean {
+ return action != KeyEvent.ACTION_DOWN
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index ff3e77c..682e841 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -28,6 +28,9 @@
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.data.repository.FacePropertyRepository
+import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -68,34 +71,32 @@
* upstream changes.
*/
interface BiometricSettingsRepository {
- /** Whether any fingerprints are enrolled for the current user. */
- val isFingerprintEnrolled: StateFlow<Boolean>
-
- /** Whether face authentication is enrolled for the current user. */
- val isFaceEnrolled: Flow<Boolean>
+ /**
+ * If the current user can enter the device using fingerprint. This is true if user has enrolled
+ * fingerprints and fingerprint auth is not disabled through settings/device policy
+ */
+ val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
/**
- * Whether face authentication is enabled/disabled based on system settings like device policy,
- * biometrics setting.
+ * If the current user can enter the device using fingerprint, right now.
+ *
+ * This returns true if there are no strong auth flags that restrict the user from using
+ * fingerprint and [isFingerprintEnrolledAndEnabled] is true
*/
- val isFaceAuthenticationEnabled: Flow<Boolean>
+ val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean>
/**
- * Whether the current user is allowed to use a strong biometric for device entry based on
- * Android Security policies. If false, the user may be able to use primary authentication for
- * device entry.
+ * If the current user can use face auth to enter the device. This is true when the user has
+ * face auth enrolled, and is enabled in settings/device policy.
*/
- val isStrongBiometricAllowed: StateFlow<Boolean>
+ val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
/**
- * Whether the current user is allowed to use a convenience biometric for device entry based on
- * Android Security policies. If false, the user may be able to use strong biometric or primary
- * authentication for device entry.
+ * If the current user can use face auth to enter the device right now. This is true when
+ * [isFaceAuthEnrolledAndEnabled] is true and strong auth settings allow face auth to run and
+ * face auth is supported by the current device posture.
*/
- val isNonStrongBiometricAllowed: StateFlow<Boolean>
-
- /** Whether fingerprint feature is enabled for the current user by the DevicePolicy */
- val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean>
+ val isFaceAuthCurrentlyAllowed: Flow<Boolean>
/**
* Whether face authentication is supported for the current device posture. Face auth can be
@@ -130,6 +131,8 @@
@Background backgroundDispatcher: CoroutineDispatcher,
biometricManager: BiometricManager?,
devicePostureRepository: DevicePostureRepository,
+ facePropertyRepository: FacePropertyRepository,
+ fingerprintPropertyRepository: FingerprintPropertyRepository,
dumpManager: DumpManager,
) : BiometricSettingsRepository, Dumpable {
@@ -165,7 +168,9 @@
}
override fun dump(pw: PrintWriter, args: Array<String?>) {
- pw.println("isFingerprintEnrolled=${isFingerprintEnrolled.value}")
+ pw.println("isFingerprintEnrolledAndEnabled=${isFingerprintEnrolledAndEnabled.value}")
+ pw.println("isFingerprintAuthCurrentlyAllowed=${isFingerprintAuthCurrentlyAllowed.value}")
+ pw.println("isNonStrongBiometricAllowed=${isNonStrongBiometricAllowed.value}")
pw.println("isStrongBiometricAllowed=${isStrongBiometricAllowed.value}")
pw.println("isFingerprintEnabledByDevicePolicy=${isFingerprintEnabledByDevicePolicy.value}")
}
@@ -180,7 +185,7 @@
user = UserHandle.ALL
)
- override val isFingerprintEnrolled: StateFlow<Boolean> =
+ private val isFingerprintEnrolled: Flow<Boolean> =
selectedUserId
.flatMapLatest { currentUserId ->
conflatedCallbackFlow {
@@ -211,7 +216,7 @@
authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id)
)
- override val isFaceEnrolled: Flow<Boolean> =
+ private val isFaceEnrolled: Flow<Boolean> =
selectedUserId.flatMapLatest { selectedUserId: Int ->
conflatedCallbackFlow {
val callback =
@@ -245,14 +250,6 @@
isFaceEnabledByBiometricsManager.map { biometricsEnabledForUser[userInfo.id] ?: false }
}
- override val isFaceAuthenticationEnabled: Flow<Boolean>
- get() =
- combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) {
- biometricsManagerSetting,
- devicePolicySetting ->
- biometricsManagerSetting && devicePolicySetting
- }
-
private val isFaceEnabledByDevicePolicy: Flow<Boolean> =
combine(selectedUserId, devicePolicyChangedForAllUsers) { userId, _ ->
devicePolicyManager.isFaceDisabled(userId)
@@ -263,6 +260,13 @@
.flowOn(backgroundDispatcher)
.distinctUntilChanged()
+ private val isFaceAuthenticationEnabled: Flow<Boolean> =
+ combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) {
+ biometricsManagerSetting,
+ devicePolicySetting ->
+ biometricsManagerSetting && devicePolicySetting
+ }
+
private val isFaceEnabledByBiometricsManager: Flow<Pair<Int, Boolean>> =
conflatedCallbackFlow {
val callback =
@@ -283,7 +287,7 @@
// being registered.
.stateIn(scope, SharingStarted.Eagerly, Pair(0, false))
- override val isStrongBiometricAllowed: StateFlow<Boolean> =
+ private val isStrongBiometricAllowed: StateFlow<Boolean> =
strongAuthTracker.isStrongBiometricAllowed.stateIn(
scope,
SharingStarted.Eagerly,
@@ -293,7 +297,7 @@
)
)
- override val isNonStrongBiometricAllowed: StateFlow<Boolean> =
+ private val isNonStrongBiometricAllowed: StateFlow<Boolean> =
strongAuthTracker.isNonStrongBiometricAllowed.stateIn(
scope,
SharingStarted.Eagerly,
@@ -303,7 +307,19 @@
)
)
- override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
+ private val isFingerprintBiometricAllowed: Flow<Boolean> =
+ fingerprintPropertyRepository.strength.flatMapLatest {
+ if (it == SensorStrength.STRONG) isStrongBiometricAllowed
+ else isNonStrongBiometricAllowed
+ }
+
+ private val isFaceBiometricsAllowed: Flow<Boolean> =
+ facePropertyRepository.sensorInfo.flatMapLatest {
+ if (it?.strength == SensorStrength.STRONG) isStrongBiometricAllowed
+ else isNonStrongBiometricAllowed
+ }
+
+ private val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
selectedUserId
.flatMapLatest { userId ->
devicePolicyChangedForAllUsers
@@ -319,6 +335,25 @@
userRepository.getSelectedUserInfo().id
)
)
+
+ override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean> =
+ isFingerprintEnrolled
+ .and(isFingerprintEnabledByDevicePolicy)
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean> =
+ isFingerprintEnrolledAndEnabled
+ .and(isFingerprintBiometricAllowed)
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ override val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
+ get() = isFaceAuthenticationEnabled.and(isFaceEnrolled)
+
+ override val isFaceAuthCurrentlyAllowed: Flow<Boolean>
+ get() =
+ isFaceAuthEnrolledAndEnabled
+ .and(isFaceBiometricsAllowed)
+ .and(isFaceAuthSupportedInCurrentPosture)
}
@OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 6894147..93eb103 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -26,8 +26,6 @@
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.Dumpable
import com.android.systemui.R
-import com.android.systemui.biometrics.data.repository.FacePropertyRepository
-import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -72,7 +70,6 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@@ -162,7 +159,6 @@
@FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val featureFlags: FeatureFlags,
- facePropertyRepository: FacePropertyRepository,
dumpManager: DumpManager,
) : DeviceEntryFaceAuthRepository, Dumpable {
private var authCancellationSignal: CancellationSignal? = null
@@ -182,13 +178,6 @@
override val detectionStatus: Flow<FaceDetectionStatus>
get() = _detectionStatus.filterNotNull()
- private val isFaceBiometricsAllowed: Flow<Boolean> =
- facePropertyRepository.sensorInfo.flatMapLatest {
- if (it?.strength == SensorStrength.STRONG)
- biometricSettingsRepository.isStrongBiometricAllowed
- else biometricSettingsRepository.isNonStrongBiometricAllowed
- }
-
private val _isLockedOut = MutableStateFlow(false)
override val isLockedOut: StateFlow<Boolean> = _isLockedOut
@@ -313,8 +302,10 @@
canFaceAuthOrDetectRun(faceDetectLog),
logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog),
logAndObserve(
- isFaceBiometricsAllowed.isFalse().or(trustRepository.isCurrentUserTrusted),
- "biometricIsNotAllowedOrCurrentUserIsTrusted",
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed
+ .isFalse()
+ .or(trustRepository.isCurrentUserTrusted),
+ "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted",
faceDetectLog
),
// We don't want to run face detect if fingerprint can be used to unlock the device
@@ -346,13 +337,8 @@
private fun canFaceAuthOrDetectRun(tableLogBuffer: TableLogBuffer): Flow<Boolean> {
return listOf(
logAndObserve(
- biometricSettingsRepository.isFaceEnrolled,
- "isFaceEnrolled",
- tableLogBuffer
- ),
- logAndObserve(
- biometricSettingsRepository.isFaceAuthenticationEnabled,
- "isFaceAuthenticationEnabled",
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
+ "isFaceAuthEnrolledAndEnabled",
tableLogBuffer
),
logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
@@ -406,7 +392,11 @@
"currentUserIsNotTrusted",
faceAuthLog
),
- logAndObserve(isFaceBiometricsAllowed, "isFaceBiometricsAllowed", faceAuthLog),
+ logAndObserve(
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
+ "isFaceAuthCurrentlyAllowed",
+ faceAuthLog
+ ),
logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog),
)
.reduce(::and)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
new file mode 100644
index 0000000..e501ece
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import android.content.Context
+import android.media.AudioManager
+import android.view.KeyEvent
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor.Companion.handleAction
+import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import javax.inject.Inject
+
+/** Handles key events arriving when the keyguard is showing or device is dozing. */
+@SysUISingleton
+class KeyguardKeyEventInteractor
+@Inject
+constructor(
+ private val context: Context,
+ private val statusBarStateController: StatusBarStateController,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+ private val shadeController: ShadeController,
+ private val mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper,
+ private val backActionInteractor: BackActionInteractor,
+) {
+
+ fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ if (statusBarStateController.isDozing) {
+ when (event.keyCode) {
+ KeyEvent.KEYCODE_VOLUME_DOWN,
+ KeyEvent.KEYCODE_VOLUME_UP -> return dispatchVolumeKeyEvent(event)
+ }
+ }
+
+ if (event.handleAction()) {
+ when (event.keyCode) {
+ KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent()
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.KEYCODE_ENTER ->
+ if (isDeviceInteractive()) {
+ return collapseShadeLockedOrShowPrimaryBouncer()
+ }
+ }
+ }
+ return false
+ }
+
+ /**
+ * While IME is active and a BACK event is detected, check with {@link
+ * StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event should be
+ * handled before routing to IME, in order to prevent the user from having to hit back twice to
+ * exit bouncer.
+ */
+ fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
+ when (event.keyCode) {
+ KeyEvent.KEYCODE_BACK ->
+ if (
+ statusBarStateController.state == StatusBarState.KEYGUARD &&
+ statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()
+ ) {
+ return backActionInteractor.onBackRequested()
+ }
+ }
+ return false
+ }
+
+ fun interceptMediaKey(event: KeyEvent): Boolean {
+ return statusBarStateController.state == StatusBarState.KEYGUARD &&
+ statusBarKeyguardViewManager.interceptMediaKey(event)
+ }
+
+ private fun dispatchMenuKeyEvent(): Boolean {
+ val shouldUnlockOnMenuPressed =
+ isDeviceInteractive() &&
+ (statusBarStateController.state != StatusBarState.SHADE) &&
+ statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
+ if (shouldUnlockOnMenuPressed) {
+ return collapseShadeLockedOrShowPrimaryBouncer()
+ }
+ return false
+ }
+
+ private fun collapseShadeLockedOrShowPrimaryBouncer(): Boolean {
+ when (statusBarStateController.state) {
+ StatusBarState.SHADE -> return false
+ StatusBarState.SHADE_LOCKED -> {
+ shadeController.animateCollapseShadeForced()
+ return true
+ }
+ StatusBarState.KEYGUARD -> {
+ statusBarKeyguardViewManager.showPrimaryBouncer(true)
+ return true
+ }
+ }
+ return false
+ }
+
+ private fun dispatchVolumeKeyEvent(event: KeyEvent): Boolean {
+ mediaSessionLegacyHelperWrapper
+ .getHelper(context)
+ .sendVolumeKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE, true)
+ return true
+ }
+
+ private fun isDeviceInteractive(): Boolean {
+ return keyguardInteractor.wakefulnessModel.value.isDeviceInteractive()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index 23b80b0..ed4dd6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -19,10 +19,10 @@
import android.os.Trace
import android.util.Log
+import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.launch
@@ -31,19 +31,19 @@
companion object {
private const val TAG = "KeyguardBlueprintViewBinder"
- fun bind(keyguardRootView: KeyguardRootView, viewModel: KeyguardBlueprintViewModel) {
- keyguardRootView.repeatWhenAttached {
+ fun bind(constraintLayout: ConstraintLayout, viewModel: KeyguardBlueprintViewModel) {
+ constraintLayout.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
viewModel.blueprint.collect { blueprint ->
Trace.beginSection("KeyguardBlueprintController#applyBlueprint")
Log.d(TAG, "applying blueprint: $blueprint")
ConstraintSet().apply {
- clone(keyguardRootView)
+ clone(constraintLayout)
val emptyLayout = ConstraintSet.Layout()
knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
blueprint?.apply(this)
- applyTo(keyguardRootView)
+ applyTo(constraintLayout)
}
Trace.endSection()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSessionLegacyHelperWrapper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSessionLegacyHelperWrapper.kt
new file mode 100644
index 0000000..9924369
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSessionLegacyHelperWrapper.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.systemui.media.controls.util
+
+import android.content.Context
+import android.media.session.MediaSessionLegacyHelper
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/** Injectable wrapper around `MediaSessionLegacyHelper` functions */
+@SysUISingleton
+class MediaSessionLegacyHelperWrapper @Inject constructor() {
+ fun getHelper(context: Context): MediaSessionLegacyHelper {
+ return MediaSessionLegacyHelper.getHelper(context)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index a3d1d8c..d8824983 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -515,11 +515,13 @@
mSeekBar.setOnTouchListener((v, event) -> false);
updateIconAreaClickListener((v) -> {
if (device.getCurrentVolume() == 0) {
+ mController.logInteractionUnmuteDevice(device);
mSeekBar.setVolume(UNMUTE_DEFAULT_VOLUME);
mController.adjustVolume(device, UNMUTE_DEFAULT_VOLUME);
updateUnmutedVolumeIcon();
mIconAreaLayout.setOnTouchListener(((iconV, event) -> false));
} else {
+ mController.logInteractionMuteDevice(device);
mSeekBar.resetVolume();
mController.adjustVolume(device, 0);
updateMutedVolumeIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index b431bab..13cd8e3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -843,6 +843,14 @@
mMetricLogger.logInteractionAdjustVolume(device);
}
+ void logInteractionMuteDevice(MediaDevice device) {
+ mMetricLogger.logInteractionMute(device);
+ }
+
+ void logInteractionUnmuteDevice(MediaDevice device) {
+ mMetricLogger.logInteractionUnmute(device);
+ }
+
String getPackageName() {
return mPackageName;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
index 412d1a3..ffd626a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -154,6 +154,38 @@
}
/**
+ * Do the metric logging of muting device.
+ */
+ public void logInteractionMute(MediaDevice source) {
+ if (DEBUG) {
+ Log.d(TAG, "logInteraction - Mute");
+ }
+
+ SysUiStatsLog.write(
+ SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
+ SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__MUTE,
+ getInteractionDeviceType(source),
+ getLoggingPackageName(),
+ source.isSuggestedDevice());
+ }
+
+ /**
+ * Do the metric logging of unmuting device.
+ */
+ public void logInteractionUnmute(MediaDevice source) {
+ if (DEBUG) {
+ Log.d(TAG, "logInteraction - Unmute");
+ }
+
+ SysUiStatsLog.write(
+ SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
+ SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__UNMUTE,
+ getInteractionDeviceType(source),
+ getLoggingPackageName(),
+ source.isSuggestedDevice());
+ }
+
+ /**
* Do the metric logging of content switching failure.
*
* @param deviceItemList media item list for device count updating
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index e134f7c..ae0ab84 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -25,6 +25,7 @@
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
import static android.view.InsetsSource.FLAG_SUPPRESS_SCRIM;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -1714,10 +1715,12 @@
private InsetsFrameProvider[] getInsetsFrameProvider(int insetsHeight, Context userContext) {
final InsetsFrameProvider navBarProvider =
- new InsetsFrameProvider(mInsetsSourceOwner, 0, WindowInsets.Type.navigationBars())
- .setInsetsSizeOverrides(new InsetsFrameProvider.InsetsSizeOverride[] {
- new InsetsFrameProvider.InsetsSizeOverride(
- TYPE_INPUT_METHOD, null)});
+ new InsetsFrameProvider(mInsetsSourceOwner, 0, WindowInsets.Type.navigationBars());
+ if (!ENABLE_HIDE_IME_CAPTION_BAR) {
+ navBarProvider.setInsetsSizeOverrides(new InsetsFrameProvider.InsetsSizeOverride[] {
+ new InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, null)
+ });
+ }
if (insetsHeight != -1 && !mEdgeBackGestureHandler.isButtonForcedVisible()) {
navBarProvider.setInsetsSize(Insets.of(0, 0, 0, insetsHeight));
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 76d9b03..a7434c6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -21,16 +21,13 @@
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -109,10 +106,6 @@
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
- private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
- /** A flow of motion events originating from outside of the scene framework. */
- val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow()
-
/**
* Returns the keys of all scenes in the container.
*
@@ -160,11 +153,6 @@
repository.setTransitionState(transitionState)
}
- /** Handles a remote user input. */
- fun onRemoteUserInput(input: RemoteUserInput) {
- _remoteUserInput.value = input
- }
-
/**
* Notifies that the UI has transitioned sufficiently to the given scene.
*
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt
deleted file mode 100644
index 680de59..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.android.systemui.scene.shared.model
-
-import android.view.MotionEvent
-
-/** A representation of user input that is used by the scene framework. */
-data class RemoteUserInput(
- val x: Float,
- val y: Float,
- val action: RemoteUserInputAction,
-) {
- companion object {
- fun translateMotionEvent(event: MotionEvent): RemoteUserInput {
- return RemoteUserInput(
- x = event.x,
- y = event.y,
- action =
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN -> RemoteUserInputAction.DOWN
- MotionEvent.ACTION_MOVE -> RemoteUserInputAction.MOVE
- MotionEvent.ACTION_UP -> RemoteUserInputAction.UP
- MotionEvent.ACTION_CANCEL -> RemoteUserInputAction.CANCEL
- else -> RemoteUserInputAction.UNKNOWN
- }
- )
- }
- }
-}
-
-enum class RemoteUserInputAction {
- DOWN,
- MOVE,
- UP,
- CANCEL,
- UNKNOWN,
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 8601b3d..cdf50ba 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -2,7 +2,6 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.MotionEvent
import android.view.View
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -39,14 +38,6 @@
)
}
- override fun onTouchEvent(event: MotionEvent?): Boolean {
- return event?.let {
- viewModel.onRemoteUserInput(event)
- true
- }
- ?: false
- }
-
override fun setVisibility(visibility: Int) {
// Do nothing. We don't want external callers to invoke this. Instead, we drive our own
// visibility from our view-binder.
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 3e9bbe4..5c16fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -16,11 +16,9 @@
package com.android.systemui.scene.ui.viewmodel
-import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
@@ -34,9 +32,6 @@
constructor(
private val interactor: SceneInteractor,
) {
- /** A flow of motion events originating from outside of the scene framework. */
- val remoteUserInput: StateFlow<RemoteUserInput?> = interactor.remoteUserInput
-
/**
* Keys of all scenes in the container.
*
@@ -68,11 +63,6 @@
interactor.setTransitionState(transitionState)
}
- /** Handles a [MotionEvent] representing remote user input. */
- fun onRemoteUserInput(event: MotionEvent) {
- interactor.onRemoteUserInput(RemoteUserInput.translateMotionEvent(event))
- }
-
companion object {
private const val SCENE_TRANSITION_LOGGING_REASON = "user input"
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index e8683fb..fb99775 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -63,6 +63,7 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setDialogTitle(R.string.screenrecord_permission_dialog_title)
+ setTitle(R.string.screenrecord_title)
setStartButtonText(R.string.screenrecord_permission_dialog_continue)
setStartButtonOnClickListener { v: View? ->
onStartRecordingClicked?.run()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index 05a0416..ab2a8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -82,11 +82,15 @@
return editIntent
.setDataAndType(uri, "image/png")
+ .putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_SCREENSHOT)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
+
+ private const val EXTRA_EDIT_SOURCE = "edit_source"
+ private const val EDIT_SOURCE_SCREENSHOT = "screenshot"
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
index 0b4b7c6..bdbc470 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -43,6 +43,7 @@
*/
public class DraggableConstraintLayout extends ConstraintLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ public static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
private static final float VELOCITY_DP_PER_MS = 1;
private static final int MAXIMUM_DISMISS_DISTANCE_DP = 400;
@@ -179,8 +180,13 @@
Region r = new Region();
Rect rect = new Rect();
for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).getGlobalVisibleRect(rect);
- r.op(rect, Region.Op.UNION);
+ View child = getChildAt(i);
+ if (child.getVisibility() == View.VISIBLE) {
+ child.getGlobalVisibleRect(rect);
+ rect.inset((int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
+ (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP));
+ r.op(rect, Region.Op.UNION);
+ }
}
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
inoutInfo.touchableRegion.set(r);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 3903bb2..03e1e15 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -68,7 +68,6 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScrollCaptureResponse;
-import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -123,7 +122,6 @@
public static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
- private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
private final Resources mResources;
private final Interpolator mFastOutSlowIn;
@@ -284,17 +282,22 @@
Region swipeRegion = new Region();
final Rect tmpRect = new Rect();
+ int swipePadding = (int) FloatingWindowUtil.dpToPx(
+ mDisplayMetrics, DraggableConstraintLayout.SWIPE_PADDING_DP * -1);
mScreenshotPreview.getBoundsOnScreen(tmpRect);
- tmpRect.inset((int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP));
+ tmpRect.inset(swipePadding, swipePadding);
swipeRegion.op(tmpRect, Region.Op.UNION);
mActionsContainerBackground.getBoundsOnScreen(tmpRect);
- tmpRect.inset((int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP));
+ tmpRect.inset(swipePadding, swipePadding);
swipeRegion.op(tmpRect, Region.Op.UNION);
mDismissButton.getBoundsOnScreen(tmpRect);
swipeRegion.op(tmpRect, Region.Op.UNION);
+ View messageContainer = findViewById(R.id.screenshot_message_container);
+ if (messageContainer != null) {
+ messageContainer.getBoundsOnScreen(tmpRect);
+ swipeRegion.op(tmpRect, Region.Op.UNION);
+ }
View messageDismiss = findViewById(R.id.message_dismiss_button);
if (messageDismiss != null) {
messageDismiss.getBoundsOnScreen(tmpRect);
@@ -378,16 +381,6 @@
mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
- int swipePaddingPx = (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, SWIPE_PADDING_DP);
- TouchDelegate previewDelegate = new TouchDelegate(
- new Rect(swipePaddingPx, swipePaddingPx, swipePaddingPx, swipePaddingPx),
- mScreenshotPreview);
- mScreenshotPreview.setTouchDelegate(previewDelegate);
- TouchDelegate actionsDelegate = new TouchDelegate(
- new Rect(swipePaddingPx, swipePaddingPx, swipePaddingPx, swipePaddingPx),
- mActionsContainerBackground);
- mActionsContainerBackground.setTouchDelegate(actionsDelegate);
-
setFocusable(true);
mActionsContainer.setScrollX(0);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 132cd61..014093d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -985,6 +985,7 @@
// Make sure the clock is in the correct position after the unlock animation
// so that it's not in the wrong place when we show the keyguard again.
positionClockAndNotifications(true /* forceClockUpdate */);
+ mScrimController.onUnlockAnimationFinished();
}
private void unlockAnimationStarted(
@@ -1243,6 +1244,13 @@
mKeyguardStatusViewController.init();
}
mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
+ mKeyguardStatusViewController.getView().addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ int oldHeight = oldBottom - oldTop;
+ if (v.getHeight() != oldHeight) {
+ mNotificationStackScrollLayoutController.animateNextTopPaddingChange();
+ }
+ });
updateClockAppearance();
@@ -3198,6 +3206,11 @@
}
}
+ @Override
+ public void performHapticFeedback(int constant) {
+ mVibratorHelper.performHapticFeedback(mView, constant);
+ }
+
private class ShadeHeadsUpTrackerImpl implements ShadeHeadsUpTracker {
@Override
public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 832a25b..798f2d5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -21,8 +21,6 @@
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.app.StatusBarManager;
-import android.media.AudioManager;
-import android.media.session.MediaSessionLegacyHelper;
import android.os.PowerManager;
import android.util.Log;
import android.view.GestureDetector;
@@ -47,6 +45,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -101,13 +100,21 @@
private final NotificationInsetsController mNotificationInsetsController;
private final boolean mIsTrackpadCommonEnabled;
private final FeatureFlags mFeatureFlags;
+ private final KeyEventInteractor mKeyEventInteractor;
private GestureDetector mPulsingWakeupGestureHandler;
private GestureDetector mDreamingWakeupGestureHandler;
private View mBrightnessMirror;
private boolean mTouchActive;
private boolean mTouchCancelled;
private MotionEvent mDownEvent;
+ // TODO rename to mLaunchAnimationRunning
private boolean mExpandAnimationRunning;
+ /**
+ * When mExpandAnimationRunning is true and the touch dispatcher receives a down even after
+ * uptime exceeds this, the dispatcher will stop blocking touches for the launch animation,
+ * which has presumabely not completed due to an error.
+ */
+ private long mLaunchAnimationTimeout;
private NotificationStackScrollLayout mStackScrollLayout;
private PhoneStatusBarViewController mStatusBarViewController;
private final CentralSurfaces mService;
@@ -164,7 +171,8 @@
FeatureFlags featureFlags,
SystemClock clock,
BouncerMessageInteractor bouncerMessageInteractor,
- BouncerLogger bouncerLogger) {
+ BouncerLogger bouncerLogger,
+ KeyEventInteractor keyEventInteractor) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
@@ -190,6 +198,7 @@
mNotificationInsetsController = notificationInsetsController;
mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
mFeatureFlags = featureFlags;
+ mKeyEventInteractor = keyEventInteractor;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -278,7 +287,12 @@
return logDownDispatch(ev, "touch cancelled", false);
}
if (mExpandAnimationRunning) {
- return logDownDispatch(ev, "expand animation running", false);
+ if (isDown && mClock.uptimeMillis() > mLaunchAnimationTimeout) {
+ mShadeLogger.d("NSWVC: launch animation timed out");
+ setExpandAnimationRunning(false);
+ } else {
+ return logDownDispatch(ev, "expand animation running", false);
+ }
}
if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
@@ -457,44 +471,17 @@
@Override
public boolean interceptMediaKey(KeyEvent event) {
- return mService.interceptMediaKey(event);
+ return mKeyEventInteractor.interceptMediaKey(event);
}
@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
- return mService.dispatchKeyEventPreIme(event);
+ return mKeyEventInteractor.dispatchKeyEventPreIme(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_BACK:
- if (!down) {
- mBackActionInteractor.onBackRequested();
- }
- return true;
- case KeyEvent.KEYCODE_MENU:
- if (!down) {
- return mService.onMenuPressed();
- }
- break;
- case KeyEvent.KEYCODE_SPACE:
- if (!down) {
- return mService.onSpacePressed();
- }
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_UP:
- if (mStatusBarStateController.isDozing()) {
- MediaSessionLegacyHelper.getHelper(mView.getContext())
- .sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
- return true;
- }
- break;
- }
- return false;
+ return mKeyEventInteractor.dispatchKeyEvent(event);
}
});
@@ -555,8 +542,12 @@
pw.println(mTouchActive);
}
- private void setExpandAnimationRunning(boolean running) {
+ @VisibleForTesting
+ void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) {
+ if (running) {
+ mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
+ }
mExpandAnimationRunning = running;
mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index bea12de..6564118 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -263,9 +263,11 @@
resources.getDimensionPixelSize(
R.dimen.shade_header_system_icons_padding_start
),
- systemIcons.paddingTop,
+ resources.getDimensionPixelSize(R.dimen.shade_header_system_icons_padding_top),
resources.getDimensionPixelSize(R.dimen.shade_header_system_icons_padding_end),
- systemIcons.paddingBottom
+ resources.getDimensionPixelSize(
+ R.dimen.shade_header_system_icons_padding_bottom
+ )
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index d5b5c87..182a676 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -248,6 +248,16 @@
/** Starts tracking a shade expansion gesture that originated from the status bar. */
fun startTrackingExpansionFromStatusBar()
+ /**
+ * Performs haptic feedback from a view with a haptic feedback constant.
+ *
+ * The implementation of this method should use the [android.view.View.performHapticFeedback]
+ * method with the provided constant.
+ *
+ * @param[constant] One of [android.view.HapticFeedbackConstants]
+ */
+ fun performHapticFeedback(constant: Int)
+
// ******* End Keyguard Section *********
/** Returns the ShadeHeadsUpTracker. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 287ac52..09b74b2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -86,6 +86,8 @@
return false
}
override fun startTrackingExpansionFromStatusBar() {}
+ override fun performHapticFeedback(constant: Int) {}
+
override val shadeHeadsUpTracker = ShadeHeadsUpTrackerEmptyImpl()
override val shadeFoldAnimator = ShadeFoldAnimatorEmptyImpl()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
index 8586828..8612cdf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
@@ -34,6 +34,7 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
import com.android.systemui.util.LargeScreenUtils;
import java.util.Objects;
@@ -44,6 +45,7 @@
private TextView mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
+ private ModernShadeCarrierGroupMobileView mModernMobileView;
private View mSpacer;
@Nullable
private CellSignalState mLastSignalState;
@@ -77,6 +79,23 @@
updateResources();
}
+ /** Removes a ModernStatusBarMobileView from the ViewGroup. */
+ public void removeModernMobileView() {
+ if (mModernMobileView != null) {
+ removeView(mModernMobileView);
+ mModernMobileView = null;
+ }
+ }
+
+ /** Adds a ModernStatusBarMobileView to the ViewGroup. */
+ public void addModernMobileView(ModernShadeCarrierGroupMobileView mobileView) {
+ mModernMobileView = mobileView;
+ mMobileGroup.setVisibility(View.GONE);
+ mSpacer.setVisibility(View.GONE);
+ mCarrierText.setVisibility(View.GONE);
+ addView(mobileView);
+ }
+
/**
* Update the state of this view
* @param state the current state of the signal for this view
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index ad49b26..98d8a53 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -16,6 +16,7 @@
package com.android.systemui.shade.carrier;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import android.annotation.MainThread;
@@ -46,8 +47,17 @@
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
import com.android.systemui.util.CarrierConfigTracker;
+import java.util.List;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -62,12 +72,16 @@
private final ActivityStarter mActivityStarter;
private final Handler mBgHandler;
+ private final Context mContext;
private final NetworkController mNetworkController;
private final CarrierTextManager mCarrierTextManager;
private final TextView mNoSimTextView;
// Non final for testing
private H mMainHandler;
private final Callback mCallback;
+ private final MobileIconsViewModel mMobileIconsViewModel;
+ private final MobileContextProvider mMobileContextProvider;
+ private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private boolean mListening;
private final CellSignalState[] mInfos =
new CellSignalState[SIM_SLOTS];
@@ -91,7 +105,7 @@
Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
return;
}
- if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ if (slotIndex == INVALID_SIM_SLOT_INDEX) {
Log.e(TAG, "Invalid SIM slot index for subscription: " + indicators.subId);
return;
}
@@ -129,15 +143,25 @@
}
}
- private ShadeCarrierGroupController(ShadeCarrierGroup view, ActivityStarter activityStarter,
- @Background Handler bgHandler, @Main Looper mainLooper,
+ private ShadeCarrierGroupController(
+ ShadeCarrierGroup view,
+ ActivityStarter activityStarter,
+ @Background Handler bgHandler,
+ @Main Looper mainLooper,
NetworkController networkController,
- CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
-
+ CarrierTextManager.Builder carrierTextManagerBuilder,
+ Context context,
+ CarrierConfigTracker carrierConfigTracker,
+ SlotIndexResolver slotIndexResolver,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ StatusBarPipelineFlags statusBarPipelineFlags
+ ) {
+ mContext = context;
mActivityStarter = activityStarter;
mBgHandler = bgHandler;
mNetworkController = networkController;
+ mStatusBarPipelineFlags = statusBarPipelineFlags;
mCarrierTextManager = carrierTextManagerBuilder
.setShowAirplaneMode(false)
.setShowMissingSim(false)
@@ -162,6 +186,14 @@
mCarrierGroups[1] = view.getCarrier2View();
mCarrierGroups[2] = view.getCarrier3View();
+ mMobileContextProvider = mobileContextProvider;
+ mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
+
+ if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ mobileUiAdapter.setShadeCarrierGroupController(this);
+ MobileIconsBinder.bind(view, mMobileIconsViewModel);
+ }
+
mCarrierDividers[0] = view.getCarrierDivider1();
mCarrierDividers[1] = view.getCarrierDivider2();
@@ -193,6 +225,50 @@
});
}
+ /** Updates the number of visible mobile icons using the new pipeline. */
+ public void updateModernMobileIcons(List<Integer> subIds) {
+ if (!mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ Log.d(TAG, "ignoring new pipeline callback because new mobile icon is disabled");
+ return;
+ }
+
+ for (ShadeCarrier carrier : mCarrierGroups) {
+ carrier.removeModernMobileView();
+ }
+
+ List<IconData> iconDataList = processSubIdList(subIds);
+
+ for (IconData iconData : iconDataList) {
+ ShadeCarrier carrier = mCarrierGroups[iconData.slotIndex];
+
+ Context mobileContext =
+ mMobileContextProvider.getMobileContextForSub(iconData.subId, mContext);
+ ModernShadeCarrierGroupMobileView modernMobileView = ModernShadeCarrierGroupMobileView
+ .constructAndBind(
+ mobileContext,
+ mMobileIconsViewModel.getLogger(),
+ "mobile_carrier_shade_group",
+ (ShadeCarrierGroupMobileIconViewModel) mMobileIconsViewModel
+ .viewModelForSub(iconData.subId,
+ StatusBarLocation.SHADE_CARRIER_GROUP)
+ );
+ carrier.addModernMobileView(modernMobileView);
+ }
+ }
+
+ @VisibleForTesting
+ List<IconData> processSubIdList(List<Integer> subIds) {
+ return subIds
+ .stream()
+ .limit(SIM_SLOTS)
+ .map(subId -> new IconData(subId, getSlotIndex(subId)))
+ .filter(iconData ->
+ iconData.slotIndex < SIM_SLOTS
+ && iconData.slotIndex != INVALID_SIM_SLOT_INDEX
+ )
+ .toList();
+ }
+
@VisibleForTesting
protected int getSlotIndex(int subscriptionId) {
return mSlotIndexResolver.getSlotIndex(subscriptionId);
@@ -269,8 +345,12 @@
}
}
- for (int i = 0; i < SIM_SLOTS; i++) {
- mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+ if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ Log.d(TAG, "ignoring old pipeline callback because new mobile icon is enabled");
+ } else {
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+ }
}
mCarrierDividers[0].setVisibility(
@@ -306,7 +386,7 @@
Log.w(TAG, "updateInfoCarrier - slot: " + slot);
continue;
}
- if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ if (slot == INVALID_SIM_SLOT_INDEX) {
Log.e(TAG,
"Invalid SIM slot index for subscription: "
+ info.subscriptionIds[i]);
@@ -385,12 +465,24 @@
private final Context mContext;
private final CarrierConfigTracker mCarrierConfigTracker;
private final SlotIndexResolver mSlotIndexResolver;
+ private final MobileUiAdapter mMobileUiAdapter;
+ private final MobileContextProvider mMobileContextProvider;
+ private final StatusBarPipelineFlags mStatusBarPipelineFlags;
@Inject
- public Builder(ActivityStarter activityStarter, @Background Handler handler,
- @Main Looper looper, NetworkController networkController,
- CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
+ public Builder(
+ ActivityStarter activityStarter,
+ @Background Handler handler,
+ @Main Looper looper,
+ NetworkController networkController,
+ CarrierTextManager.Builder carrierTextControllerBuilder,
+ Context context,
+ CarrierConfigTracker carrierConfigTracker,
+ SlotIndexResolver slotIndexResolver,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ StatusBarPipelineFlags statusBarPipelineFlags
+ ) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
@@ -399,6 +491,9 @@
mContext = context;
mCarrierConfigTracker = carrierConfigTracker;
mSlotIndexResolver = slotIndexResolver;
+ mMobileUiAdapter = mobileUiAdapter;
+ mMobileContextProvider = mobileContextProvider;
+ mStatusBarPipelineFlags = statusBarPipelineFlags;
}
public Builder setShadeCarrierGroup(ShadeCarrierGroup view) {
@@ -407,9 +502,20 @@
}
public ShadeCarrierGroupController build() {
- return new ShadeCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
- mNetworkController, mCarrierTextControllerBuilder, mContext,
- mCarrierConfigTracker, mSlotIndexResolver);
+ return new ShadeCarrierGroupController(
+ mView,
+ mActivityStarter,
+ mHandler,
+ mLooper,
+ mNetworkController,
+ mCarrierTextControllerBuilder,
+ mContext,
+ mCarrierConfigTracker,
+ mSlotIndexResolver,
+ mMobileUiAdapter,
+ mMobileContextProvider,
+ mStatusBarPipelineFlags
+ );
}
}
@@ -448,4 +554,15 @@
return SubscriptionManager.getSlotIndex(subscriptionId);
}
}
+
+ @VisibleForTesting
+ static class IconData {
+ public final int subId;
+ public final int slotIndex;
+
+ IconData(int subId, int slotIndex) {
+ this.subId = subId;
+ this.slotIndex = slotIndex;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
index d3c19b7..5042f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -31,56 +31,68 @@
) {
fun logInitialClick(
entry: NotificationEntry?,
+ index: Integer?,
pendingIntent: PendingIntent
) {
buffer.log(TAG, LogLevel.DEBUG, {
str1 = entry?.key
str2 = entry?.ranking?.channel?.id
- str3 = pendingIntent.intent.toString()
+ str3 = pendingIntent.toString()
+ int1 = index?.toInt() ?: Int.MIN_VALUE
}, {
- "ACTION CLICK $str1 (channel=$str2) for pending intent $str3"
+ "ACTION CLICK $str1 (channel=$str2) for pending intent $str3 at index $int1"
})
}
fun logRemoteInputWasHandled(
- entry: NotificationEntry?
+ entry: NotificationEntry?,
+ index: Int?
) {
buffer.log(TAG, LogLevel.DEBUG, {
str1 = entry?.key
+ int1 = index ?: Int.MIN_VALUE
}, {
- " [Action click] Triggered remote input (for $str1))"
+ " [Action click] Triggered remote input (for $str1) at index $int1"
})
}
fun logStartingIntentWithDefaultHandler(
entry: NotificationEntry?,
- pendingIntent: PendingIntent
+ pendingIntent: PendingIntent,
+ index: Int?
) {
buffer.log(TAG, LogLevel.DEBUG, {
str1 = entry?.key
- str2 = pendingIntent.intent.toString()
+ str2 = pendingIntent.toString()
+ int1 = index ?: Int.MIN_VALUE
}, {
- " [Action click] Launching intent $str2 via default handler (for $str1)"
+ " [Action click] Launching intent $str2 via default handler (for $str1 at index $int1)"
})
}
fun logWaitingToCloseKeyguard(
- pendingIntent: PendingIntent
+ pendingIntent: PendingIntent,
+ index: Int?
) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = pendingIntent.intent.toString()
+ str1 = pendingIntent.toString()
+ int1 = index ?: Int.MIN_VALUE
}, {
- " [Action click] Intent $str1 launches an activity, dismissing keyguard first..."
+ " [Action click] Intent $str1 at index $int1 launches an activity, dismissing " +
+ "keyguard first..."
})
}
fun logKeyguardGone(
- pendingIntent: PendingIntent
+ pendingIntent: PendingIntent,
+ index: Int?
) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = pendingIntent.intent.toString()
+ str1 = pendingIntent.toString()
+ int1 = index ?: Int.MIN_VALUE
}, {
- " [Action click] Keyguard dismissed, calling default handler for intent $str1"
+ " [Action click] Keyguard dismissed, calling default handler for intent $str1 at " +
+ "index $int1"
})
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
index abf81c5..692a997 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
@@ -2,10 +2,12 @@
import android.app.Notification
import android.os.RemoteException
+import android.util.Log
import com.android.internal.statusbar.IStatusBarService
import com.android.internal.statusbar.NotificationVisibility
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.util.Assert
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -21,7 +23,8 @@
@SysUISingleton
public class NotificationClickNotifier @Inject constructor(
val barService: IStatusBarService,
- @Main val mainExecutor: Executor
+ @Main val mainExecutor: Executor,
+ @UiBackground val backgroundExecutor: Executor
) {
val listeners = mutableListOf<NotificationInteractionListener>()
@@ -48,13 +51,14 @@
visibility: NotificationVisibility,
generatedByAssistant: Boolean
) {
- try {
- barService.onNotificationActionClick(
- key, actionIndex, action, visibility, generatedByAssistant)
- } catch (e: RemoteException) {
- // nothing
+ backgroundExecutor.execute {
+ try {
+ barService.onNotificationActionClick(
+ key, actionIndex, action, visibility, generatedByAssistant)
+ } catch (e: RemoteException) {
+ // nothing
+ }
}
-
mainExecutor.execute {
notifyListenersAboutInteraction(key)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index da84afe..8089fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -119,11 +119,14 @@
mPowerInteractor.wakeUpIfDozing(
"NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE);
+ Integer actionIndex = (Integer)
+ view.getTag(com.android.internal.R.id.notification_action_index_tag);
+
final NotificationEntry entry = getNotificationForParent(view.getParent());
- mLogger.logInitialClick(entry, pendingIntent);
+ mLogger.logInitialClick(entry, actionIndex, pendingIntent);
if (handleRemoteInput(view, pendingIntent)) {
- mLogger.logRemoteInputWasHandled(entry);
+ mLogger.logRemoteInputWasHandled(entry, actionIndex);
return true;
}
@@ -141,9 +144,9 @@
}
Notification.Action action = getActionFromView(view, entry, pendingIntent);
return mCallback.handleRemoteViewClick(view, pendingIntent,
- action == null ? false : action.isAuthenticationRequired(), () -> {
+ action == null ? false : action.isAuthenticationRequired(), actionIndex, () -> {
Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
- mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent);
+ mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent, actionIndex);
boolean started = RemoteViews.startPendingIntent(view, pendingIntent, options);
if (started) releaseNotificationIfKeptForRemoteInputHistory(entry);
return started;
@@ -692,11 +695,13 @@
* @param view
* @param pendingIntent
* @param appRequestedAuth
+ * @param actionIndex
* @param defaultHandler
* @return true iff the click was handled
*/
boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
- boolean appRequestedAuth, ClickHandler defaultHandler);
+ boolean appRequestedAuth, @Nullable Integer actionIndex,
+ ClickHandler defaultHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index d6a14604..6dd24ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -48,8 +48,10 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardClockSwitch;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -420,6 +422,25 @@
}
}
+ /** Returns the id of the currently rendering clock */
+ public String getClockId() {
+ if (mView == null) {
+ return KeyguardClockSwitch.MISSING_CLOCK_ID;
+ }
+
+ View clockSwitch = mView.findViewById(R.id.keyguard_clock_container);
+ if (clockSwitch == null) {
+ Log.e(TAG, "Clock container was missing");
+ return KeyguardClockSwitch.MISSING_CLOCK_ID;
+ }
+ if (!(clockSwitch instanceof KeyguardClockSwitch)) {
+ Log.e(TAG, "Clock container was incorrect type: " + clockSwitch);
+ return KeyguardClockSwitch.MISSING_CLOCK_ID;
+ }
+
+ return ((KeyguardClockSwitch) clockSwitch).getClockId();
+ }
+
private void beginInteractionJankMonitor() {
final boolean shouldPost =
(mIsDozing && mDozeAmount == 0) || (!mIsDozing && mDozeAmount == 1);
@@ -429,6 +450,7 @@
Choreographer.CALLBACK_ANIMATION, this::beginInteractionJankMonitor, null);
} else {
Configuration.Builder builder = Configuration.Builder.withView(getCujType(), mView)
+ .setTag(getClockId())
.setDeferMonitorForAnimationStart(false);
mInteractionJankMonitor.begin(builder);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 5c2f9a8..62a0d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -39,10 +39,7 @@
override fun attach(pipeline: NotifPipeline) {
pipeline.addOnAfterRenderListListener(::onAfterRenderList)
- // TODO(b/282865576): This has an issue where it makes changes to some groups without
- // notifying listeners. To be fixed in QPR, but for now let's comment it out to avoid the
- // group expansion bug.
- // groupExpansionManagerImpl.attach(pipeline)
+ groupExpansionManagerImpl.attach(pipeline)
}
fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index 46af03a..5d33804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -67,18 +67,29 @@
* Cleanup entries from mExpandedGroups that no longer exist in the pipeline.
*/
private final OnBeforeRenderListListener mNotifTracker = (entries) -> {
+ if (mExpandedGroups.isEmpty()) {
+ return; // nothing to do
+ }
+
final Set<NotificationEntry> renderingSummaries = new HashSet<>();
for (ListEntry entry : entries) {
if (entry instanceof GroupEntry) {
renderingSummaries.add(entry.getRepresentativeEntry());
}
}
- mExpandedGroups.removeIf(expandedGroup -> !renderingSummaries.contains(expandedGroup));
+
+ // Create a copy of mExpandedGroups so we can modify it in a thread-safe way.
+ final var currentExpandedGroups = new HashSet<>(mExpandedGroups);
+ for (NotificationEntry entry : currentExpandedGroups) {
+ setExpanded(entry, renderingSummaries.contains(entry));
+ }
};
public void attach(NotifPipeline pipeline) {
- mDumpManager.registerDumpable(this);
- pipeline.addOnBeforeRenderListListener(mNotifTracker);
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+ mDumpManager.registerDumpable(this);
+ pipeline.addOnBeforeRenderListListener(mNotifTracker);
+ }
}
@Override
@@ -94,11 +105,24 @@
@Override
public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
final NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry);
+ setExpanded(groupSummary, expanded);
+ }
+
+ /**
+ * Add or remove {@code entry} to/from {@code mExpandedGroups} and notify listeners if
+ * something changed. This assumes that {@code entry} is a group summary.
+ * <p>
+ * TODO(b/293434635): Currently, in spite of its docs,
+ * {@code mGroupMembershipManager.getGroupSummary(entry)} returns null if {@code entry} is
+ * already a summary. Instead of needing this helper method to bypass that, we probably want to
+ * move this code back to {@code setGroupExpanded} and use that everywhere.
+ */
+ private void setExpanded(NotificationEntry entry, boolean expanded) {
boolean changed;
if (expanded) {
- changed = mExpandedGroups.add(groupSummary);
+ changed = mExpandedGroups.add(entry);
} else {
- changed = mExpandedGroups.remove(groupSummary);
+ changed = mExpandedGroups.remove(entry);
}
// Only notify listeners if something changed.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
new file mode 100644
index 0000000..26dfe3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -0,0 +1,684 @@
+/*
+ * 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.statusbar.notification.icon.ui.viewbinder
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.Rect
+import android.os.Bundle
+import android.os.Trace
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.annotation.ColorInt
+import androidx.annotation.VisibleForTesting
+import androidx.collection.ArrayMap
+import com.android.app.animation.Interpolators
+import com.android.internal.statusbar.StatusBarIcon
+import com.android.internal.util.ContrastColorUtil
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ViewRefactorFlag
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.CrossFadeHelper
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.NotificationShelfController
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
+import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import java.util.function.Function
+import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
+
+/**
+ * Controller class for [NotificationIconContainer]. This implementation serves as a temporary
+ * wrapper around [NotificationIconContainerViewBinder], so that external code can continue to
+ * depend on the [NotificationIconAreaController] interface. Once
+ * [LegacyNotificationIconAreaControllerImpl] is removed, this class can go away and the ViewBinder
+ * can be used directly.
+ */
+@SysUISingleton
+class NotificationIconAreaControllerViewBinderWrapperImpl
+@Inject
+constructor(
+ private val context: Context,
+ private val statusBarStateController: StatusBarStateController,
+ private val wakeUpCoordinator: NotificationWakeUpCoordinator,
+ private val bypassController: KeyguardBypassController,
+ private val mediaManager: NotificationMediaManager,
+ notificationListener: NotificationListener,
+ private val dozeParameters: DozeParameters,
+ private val sectionStyleProvider: SectionStyleProvider,
+ private val bubblesOptional: Optional<Bubbles>,
+ demoModeController: DemoModeController,
+ darkIconDispatcher: DarkIconDispatcher,
+ featureFlags: FeatureFlags,
+ private val statusBarWindowController: StatusBarWindowController,
+ private val screenOffAnimationController: ScreenOffAnimationController,
+ private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
+ private val statusBarIconsViewModel: NotificationIconContainerStatusBarViewModel,
+ private val aodIconsViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
+) :
+ NotificationIconAreaController,
+ DarkIconDispatcher.DarkReceiver,
+ StatusBarStateController.StateListener,
+ NotificationWakeUpCoordinator.WakeUpListener,
+ DemoMode {
+
+ private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context)
+ private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }
+ private val shelfRefactor = ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
+ private val tintAreas = ArrayList<Rect>()
+
+ private var iconSize = 0
+ private var iconHPadding = 0
+ private var iconTint = Color.WHITE
+ private var notificationEntries = listOf<ListEntry>()
+ private var notificationIconArea: View? = null
+ private var notificationIcons: NotificationIconContainer? = null
+ private var shelfIcons: NotificationIconContainer? = null
+ private var aodIcons: NotificationIconContainer? = null
+ private var aodBindJob: DisposableHandle? = null
+ private var aodIconAppearTranslation = 0
+ private var animationsEnabled = false
+ private var aodIconTint = 0
+ private var aodIconsVisible = false
+ private var showLowPriority = true
+
+ @VisibleForTesting
+ val settingsListener: NotificationListener.NotificationSettingsListener =
+ object : NotificationListener.NotificationSettingsListener {
+ override fun onStatusBarIconsBehaviorChanged(hideSilentStatusIcons: Boolean) {
+ showLowPriority = !hideSilentStatusIcons
+ updateStatusBarIcons()
+ }
+ }
+
+ init {
+ statusBarStateController.addCallback(this)
+ wakeUpCoordinator.addListener(this)
+ demoModeController.addCallback(this)
+ notificationListener.addNotificationSettingsListener(settingsListener)
+ initializeNotificationAreaViews(context)
+ reloadAodColor()
+ darkIconDispatcher.addDarkReceiver(this)
+ }
+
+ @VisibleForTesting
+ fun shouldShowLowPriorityIcons(): Boolean {
+ return showLowPriority
+ }
+
+ /** Called by the Keyguard*ViewController whose view contains the aod icons. */
+ override fun setupAodIcons(aodIcons: NotificationIconContainer) {
+ val changed = this.aodIcons != null && aodIcons !== this.aodIcons
+ if (changed) {
+ this.aodIcons!!.setAnimationsEnabled(false)
+ this.aodIcons!!.removeAllViews()
+ aodBindJob?.dispose()
+ }
+ this.aodIcons = aodIcons
+ this.aodIcons!!.setOnLockScreen(true)
+ aodBindJob = NotificationIconContainerViewBinder.bind(aodIcons, aodIconsViewModel)
+ updateAodIconsVisibility(animate = false, forceUpdate = changed)
+ updateAnimations()
+ if (changed) {
+ updateAodNotificationIcons()
+ }
+ updateIconLayoutParams(context)
+ }
+
+ override fun setupShelf(notificationShelfController: NotificationShelfController) =
+ NotificationShelfViewBinderWrapperControllerImpl.unsupported
+
+ override fun setShelfIcons(icons: NotificationIconContainer) {
+ if (shelfRefactor.expectEnabled()) {
+ NotificationIconContainerViewBinder.bind(icons, shelfIconsViewModel)
+ shelfIcons = icons
+ }
+ }
+
+ override fun onDensityOrFontScaleChanged(context: Context) {
+ updateIconLayoutParams(context)
+ }
+
+ /** Returns the view that represents the notification area. */
+ override fun getNotificationInnerAreaView(): View? {
+ return notificationIconArea
+ }
+
+ /**
+ * See [com.android.systemui.statusbar.policy.DarkIconDispatcher.setIconsDarkArea]. Sets the
+ * color that should be used to tint any icons in the notification area.
+ *
+ * @param tintAreas the areas in which to tint the icons, specified in screen coordinates
+ * @param darkIntensity
+ */
+ override fun onDarkChanged(tintAreas: ArrayList<Rect>, darkIntensity: Float, iconTint: Int) {
+ this.tintAreas.clear()
+ this.tintAreas.addAll(tintAreas)
+ if (DarkIconDispatcher.isInAreas(tintAreas, notificationIconArea)) {
+ this.iconTint = iconTint
+ }
+ applyNotificationIconsTint()
+ }
+
+ /** Updates the notifications with the given list of notifications to display. */
+ override fun updateNotificationIcons(entries: List<ListEntry>) {
+ notificationEntries = entries
+ updateNotificationIcons()
+ }
+
+ private fun updateStatusBarIcons() {
+ updateIconsForLayout(
+ { entry: NotificationEntry -> entry.icons.statusBarIcon },
+ notificationIcons,
+ showAmbient = false /* showAmbient */,
+ showLowPriority = showLowPriority,
+ hideDismissed = true /* hideDismissed */,
+ hideRepliedMessages = true /* hideRepliedMessages */,
+ hideCurrentMedia = false /* hideCurrentMedia */,
+ hidePulsing = false /* hidePulsing */
+ )
+ }
+
+ override fun updateAodNotificationIcons() {
+ if (aodIcons == null) {
+ return
+ }
+ updateIconsForLayout(
+ { entry: NotificationEntry -> entry.icons.aodIcon },
+ aodIcons,
+ showAmbient = false /* showAmbient */,
+ showLowPriority = true /* showLowPriority */,
+ hideDismissed = true /* hideDismissed */,
+ hideRepliedMessages = true /* hideRepliedMessages */,
+ hideCurrentMedia = true /* hideCurrentMedia */,
+ hidePulsing = bypassController.bypassEnabled /* hidePulsing */
+ )
+ }
+
+ override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) {
+ notificationIcons!!.showIconIsolated(icon, animated)
+ }
+
+ override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) {
+ notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)
+ }
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ if (aodIcons == null) {
+ return
+ }
+ val animate = (dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking)
+ aodIcons!!.setDozing(isDozing, animate, 0)
+ }
+
+ override fun setAnimationsEnabled(enabled: Boolean) {
+ animationsEnabled = enabled
+ updateAnimations()
+ }
+
+ override fun onStateChanged(newState: Int) {
+ updateAodIconsVisibility(animate = false, forceUpdate = false)
+ updateAnimations()
+ }
+
+ override fun onThemeChanged() {
+ reloadAodColor()
+ updateAodIconColors()
+ }
+
+ override fun getHeight(): Int {
+ return if (aodIcons == null) 0 else aodIcons!!.height
+ }
+
+ @VisibleForTesting
+ fun appearAodIcons() {
+ if (aodIcons == null) {
+ return
+ }
+ if (screenOffAnimationController.shouldAnimateAodIcons()) {
+ aodIcons!!.translationY = -aodIconAppearTranslation.toFloat()
+ aodIcons!!.alpha = 0f
+ animateInAodIconTranslation()
+ aodIcons!!
+ .animate()
+ .alpha(1f)
+ .setInterpolator(Interpolators.LINEAR)
+ .setDuration(AOD_ICONS_APPEAR_DURATION)
+ .start()
+ } else {
+ aodIcons!!.alpha = 1.0f
+ aodIcons!!.translationY = 0f
+ }
+ }
+
+ override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+ var animate = true
+ if (!bypassController.bypassEnabled) {
+ animate = dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking
+ // We only want the appear animations to happen when the notifications get fully hidden,
+ // since otherwise the unhide animation overlaps
+ animate = animate and isFullyHidden
+ }
+ updateAodIconsVisibility(animate, false /* force */)
+ updateAodNotificationIcons()
+ updateAodIconColors()
+ }
+
+ override fun onPulseExpansionChanged(expandingChanged: Boolean) {
+ if (expandingChanged) {
+ updateAodIconsVisibility(animate = true, forceUpdate = false)
+ }
+ }
+
+ override fun demoCommands(): List<String> {
+ val commands = ArrayList<String>()
+ commands.add(DemoMode.COMMAND_NOTIFICATIONS)
+ return commands
+ }
+
+ override fun dispatchDemoCommand(command: String, args: Bundle) {
+ if (notificationIconArea != null) {
+ val visible = args.getString("visible")
+ val vis = if ("false" == visible) View.INVISIBLE else View.VISIBLE
+ notificationIconArea?.visibility = vis
+ }
+ }
+
+ override fun onDemoModeFinished() {
+ if (notificationIconArea != null) {
+ notificationIconArea?.visibility = View.VISIBLE
+ }
+ }
+
+ private fun inflateIconArea(inflater: LayoutInflater): View {
+ return inflater.inflate(R.layout.notification_icon_area, null)
+ }
+
+ /** Initializes the views that will represent the notification area. */
+ private fun initializeNotificationAreaViews(context: Context) {
+ reloadDimens(context)
+ val layoutInflater = LayoutInflater.from(context)
+ notificationIconArea = inflateIconArea(layoutInflater)
+ notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons)
+ NotificationIconContainerViewBinder.bind(notificationIcons!!, statusBarIconsViewModel)
+ }
+
+ private fun updateIconLayoutParams(context: Context) {
+ reloadDimens(context)
+ val params = generateIconLayoutParams()
+ for (i in 0 until notificationIcons!!.childCount) {
+ val child = notificationIcons!!.getChildAt(i)
+ child.layoutParams = params
+ }
+ if (shelfIcons != null) {
+ for (i in 0 until shelfIcons!!.childCount) {
+ val child = shelfIcons!!.getChildAt(i)
+ child.layoutParams = params
+ }
+ }
+ if (aodIcons != null) {
+ for (i in 0 until aodIcons!!.childCount) {
+ val child = aodIcons!!.getChildAt(i)
+ child.layoutParams = params
+ }
+ }
+ }
+
+ private fun generateIconLayoutParams(): FrameLayout.LayoutParams {
+ return FrameLayout.LayoutParams(
+ iconSize + 2 * iconHPadding,
+ statusBarWindowController.statusBarHeight
+ )
+ }
+
+ private fun reloadDimens(context: Context) {
+ val res = context.resources
+ iconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp)
+ iconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin)
+ aodIconAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation)
+ }
+
+ private fun shouldShowNotificationIcon(
+ entry: NotificationEntry,
+ showAmbient: Boolean,
+ showLowPriority: Boolean,
+ hideDismissed: Boolean,
+ hideRepliedMessages: Boolean,
+ hideCurrentMedia: Boolean,
+ hidePulsing: Boolean
+ ): Boolean {
+ if (!showAmbient && sectionStyleProvider.isMinimized(entry)) {
+ return false
+ }
+ if (hideCurrentMedia && entry.key == mediaManager.mediaNotificationKey) {
+ return false
+ }
+ if (!showLowPriority && sectionStyleProvider.isSilent(entry)) {
+ return false
+ }
+ if (entry.isRowDismissed && hideDismissed) {
+ return false
+ }
+ if (hideRepliedMessages && entry.isLastMessageFromReply) {
+ return false
+ }
+ // showAmbient == show in shade but not shelf
+ if (!showAmbient && entry.shouldSuppressStatusBar()) {
+ return false
+ }
+ if (
+ hidePulsing &&
+ entry.showingPulsing() &&
+ (!wakeUpCoordinator.notificationsFullyHidden || !entry.isPulseSuppressed)
+ ) {
+ return false
+ }
+ return if (bubblesOptional.isPresent && bubblesOptional.get().isBubbleExpanded(entry.key)) {
+ false
+ } else true
+ }
+
+ private fun updateNotificationIcons() {
+ Trace.beginSection("NotificationIconAreaController.updateNotificationIcons")
+ updateStatusBarIcons()
+ updateShelfIcons()
+ updateAodNotificationIcons()
+ applyNotificationIconsTint()
+ Trace.endSection()
+ }
+
+ private fun updateShelfIcons() {
+ if (shelfIcons == null) {
+ return
+ }
+ updateIconsForLayout(
+ { entry: NotificationEntry -> entry.icons.shelfIcon },
+ shelfIcons,
+ showAmbient = true,
+ showLowPriority = true,
+ hideDismissed = false,
+ hideRepliedMessages = false,
+ hideCurrentMedia = false,
+ hidePulsing = false
+ )
+ }
+
+ /**
+ * Updates the notification icons for a host layout. This will ensure that the notification host
+ * layout will have the same icons like the ones in here.
+ *
+ * @param function A function to look up an icon view based on an entry
+ * @param hostLayout which layout should be updated
+ * @param showAmbient should ambient notification icons be shown
+ * @param showLowPriority should icons from silent notifications be shown
+ * @param hideDismissed should dismissed icons be hidden
+ * @param hideRepliedMessages should messages that have been replied to be hidden
+ * @param hidePulsing should pulsing notifications be hidden
+ */
+ private fun updateIconsForLayout(
+ function: Function<NotificationEntry, StatusBarIconView?>,
+ hostLayout: NotificationIconContainer?,
+ showAmbient: Boolean,
+ showLowPriority: Boolean,
+ hideDismissed: Boolean,
+ hideRepliedMessages: Boolean,
+ hideCurrentMedia: Boolean,
+ hidePulsing: Boolean,
+ ) {
+ val toShow = ArrayList<StatusBarIconView>(notificationEntries.size)
+ // Filter out ambient notifications and notification children.
+ for (i in notificationEntries.indices) {
+ val entry = notificationEntries[i].representativeEntry
+ if (entry != null && entry.row != null) {
+ if (
+ shouldShowNotificationIcon(
+ entry,
+ showAmbient,
+ showLowPriority,
+ hideDismissed,
+ hideRepliedMessages,
+ hideCurrentMedia,
+ hidePulsing
+ )
+ ) {
+ val iconView = function.apply(entry)
+ if (iconView != null) {
+ toShow.add(iconView)
+ }
+ }
+ }
+ }
+
+ // In case we are changing the suppression of a group, the replacement shouldn't flicker
+ // and it should just be replaced instead. We therefore look for notifications that were
+ // just replaced by the child or vice-versa to suppress this.
+ val replacingIcons = ArrayMap<String, ArrayList<StatusBarIcon>>()
+ val toRemove = ArrayList<View>()
+ for (i in 0 until hostLayout!!.childCount) {
+ val child = hostLayout.getChildAt(i) as? StatusBarIconView ?: continue
+ if (!toShow.contains(child)) {
+ var iconWasReplaced = false
+ val removedGroupKey = child.notification.groupKey
+ for (j in toShow.indices) {
+ val candidate = toShow[j]
+ if (
+ candidate.sourceIcon.sameAs(child.sourceIcon) &&
+ candidate.notification.groupKey == removedGroupKey
+ ) {
+ if (!iconWasReplaced) {
+ iconWasReplaced = true
+ } else {
+ iconWasReplaced = false
+ break
+ }
+ }
+ }
+ if (iconWasReplaced) {
+ var statusBarIcons = replacingIcons[removedGroupKey]
+ if (statusBarIcons == null) {
+ statusBarIcons = ArrayList()
+ replacingIcons[removedGroupKey] = statusBarIcons
+ }
+ statusBarIcons.add(child.statusBarIcon)
+ }
+ toRemove.add(child)
+ }
+ }
+ // removing all duplicates
+ val duplicates = ArrayList<String?>()
+ for (key in replacingIcons.keys) {
+ val statusBarIcons = replacingIcons[key]!!
+ if (statusBarIcons.size != 1) {
+ duplicates.add(key)
+ }
+ }
+ replacingIcons.removeAll(duplicates)
+ hostLayout.setReplacingIcons(replacingIcons)
+ val toRemoveCount = toRemove.size
+ for (i in 0 until toRemoveCount) {
+ hostLayout.removeView(toRemove[i])
+ }
+ val params = generateIconLayoutParams()
+ for (i in toShow.indices) {
+ val v = toShow[i]
+ // The view might still be transiently added if it was just removed and added again
+ hostLayout.removeTransientView(v)
+ if (v.parent == null) {
+ if (hideDismissed) {
+ v.setOnDismissListener(updateStatusBarIcons)
+ }
+ hostLayout.addView(v, i, params)
+ }
+ }
+ hostLayout.setChangingViewPositions(true)
+ // Re-sort notification icons
+ val childCount = hostLayout.childCount
+ for (i in 0 until childCount) {
+ val actual = hostLayout.getChildAt(i)
+ val expected = toShow[i]
+ if (actual === expected) {
+ continue
+ }
+ hostLayout.removeView(expected)
+ hostLayout.addView(expected, i)
+ }
+ hostLayout.setChangingViewPositions(false)
+ hostLayout.setReplacingIcons(null)
+ }
+
+ /** Applies [.mIconTint] to the notification icons. */
+ private fun applyNotificationIconsTint() {
+ for (i in 0 until notificationIcons!!.childCount) {
+ val iv = notificationIcons!!.getChildAt(i) as StatusBarIconView
+ if (iv.width != 0) {
+ updateTintForIcon(iv, iconTint)
+ } else {
+ iv.executeOnLayout { updateTintForIcon(iv, iconTint) }
+ }
+ }
+ updateAodIconColors()
+ }
+
+ private fun updateTintForIcon(v: StatusBarIconView, tint: Int) {
+ val isPreL = java.lang.Boolean.TRUE == v.getTag(R.id.icon_is_pre_L)
+ var color = StatusBarIconView.NO_COLOR
+ val colorize = !isPreL || NotificationUtils.isGrayscale(v, contrastColorUtil)
+ if (colorize) {
+ color = DarkIconDispatcher.getTint(tintAreas, v, tint)
+ }
+ v.staticDrawableColor = color
+ v.setDecorColor(tint)
+ }
+
+ private fun updateAnimations() {
+ val inShade = statusBarStateController.state == StatusBarState.SHADE
+ if (aodIcons != null) {
+ aodIcons!!.setAnimationsEnabled(animationsEnabled && !inShade)
+ }
+ notificationIcons!!.setAnimationsEnabled(animationsEnabled && inShade)
+ }
+
+ private fun animateInAodIconTranslation() {
+ aodIcons!!
+ .animate()
+ .setInterpolator(Interpolators.DECELERATE_QUINT)
+ .translationY(0f)
+ .setDuration(AOD_ICONS_APPEAR_DURATION)
+ .start()
+ }
+
+ private fun reloadAodColor() {
+ aodIconTint =
+ Utils.getColorAttrDefaultColor(
+ context,
+ R.attr.wallpaperTextColor,
+ DEFAULT_AOD_ICON_COLOR
+ )
+ }
+
+ private fun updateAodIconColors() {
+ if (aodIcons != null) {
+ for (i in 0 until aodIcons!!.childCount) {
+ val iv = aodIcons!!.getChildAt(i) as StatusBarIconView
+ if (iv.width != 0) {
+ updateTintForIcon(iv, aodIconTint)
+ } else {
+ iv.executeOnLayout { updateTintForIcon(iv, aodIconTint) }
+ }
+ }
+ }
+ }
+
+ private fun updateAodIconsVisibility(animate: Boolean, forceUpdate: Boolean) {
+ if (aodIcons == null) {
+ return
+ }
+ var visible = (bypassController.bypassEnabled || wakeUpCoordinator.notificationsFullyHidden)
+
+ // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off animation is
+ // playing, in which case we want them to be visible since we're animating in the AOD UI and
+ // will be switching to KEYGUARD shortly.
+ if (
+ statusBarStateController.state != StatusBarState.KEYGUARD &&
+ !screenOffAnimationController.shouldShowAodIconsWhenShade()
+ ) {
+ visible = false
+ }
+ if (visible && wakeUpCoordinator.isPulseExpanding() && !bypassController.bypassEnabled) {
+ visible = false
+ }
+ if (aodIconsVisible != visible || forceUpdate) {
+ aodIconsVisible = visible
+ aodIcons!!.animate().cancel()
+ if (animate) {
+ val wasFullyInvisible = aodIcons!!.visibility != View.VISIBLE
+ if (aodIconsVisible) {
+ if (wasFullyInvisible) {
+ // No fading here, let's just appear the icons instead!
+ aodIcons!!.visibility = View.VISIBLE
+ aodIcons!!.alpha = 1.0f
+ appearAodIcons()
+ } else {
+ // Let's make sure the icon are translated to 0, since we cancelled it above
+ animateInAodIconTranslation()
+ // We were fading out, let's fade in instead
+ CrossFadeHelper.fadeIn(aodIcons)
+ }
+ } else {
+ // Let's make sure the icon are translated to 0, since we cancelled it above
+ animateInAodIconTranslation()
+ CrossFadeHelper.fadeOut(aodIcons)
+ }
+ } else {
+ aodIcons!!.alpha = 1.0f
+ aodIcons!!.translationY = 0f
+ aodIcons!!.visibility = if (visible) View.VISIBLE else View.INVISIBLE
+ }
+ }
+ }
+
+ companion object {
+ private const val AOD_ICONS_APPEAR_DURATION: Long = 200
+
+ @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
new file mode 100644
index 0000000..8293bb3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.statusbar.notification.icon.ui.viewbinder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import kotlinx.coroutines.DisposableHandle
+
+/** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
+object NotificationIconContainerViewBinder {
+ fun bind(
+ view: NotificationIconContainer,
+ viewModel: NotificationIconContainerViewModel,
+ ): DisposableHandle {
+ return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) {} }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
new file mode 100644
index 0000000..f68b0ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the row of notification icons displayed on the always-on display. */
+class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor() :
+ NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
new file mode 100644
index 0000000..933c76f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the overflow row of notification icons displayed in the notification shade. */
+class NotificationIconContainerShelfViewModel @Inject constructor() :
+ NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
new file mode 100644
index 0000000..2217646
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the row of notification icons displayed in the status bar, */
+class NotificationIconContainerStatusBarViewModel @Inject constructor() :
+ NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
new file mode 100644
index 0000000..892b2be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+/**
+ * View-model for the row of notification icons displayed in the NotificationShelf, StatusBar, and
+ * AOD.
+ */
+interface NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 22a87a7..b92c51f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -64,8 +64,10 @@
override fun setOnClickListener(listener: View.OnClickListener) = unsupported
- private val unsupported: Nothing
- get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
+ companion object {
+ val unsupported: Nothing
+ get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
+ }
}
/** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 4668aa4..6db8df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -28,7 +28,6 @@
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_HIGH_PRIORITY;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.SelectedRows;
-import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.content.res.Configuration;
@@ -150,6 +149,7 @@
public class NotificationStackScrollLayoutController {
private static final String TAG = "StackScrollerController";
private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
+ private static final String HIGH_PRIORITY = "high_priority";
private final boolean mAllowLongPress;
private final NotificationGutsManager mNotificationGutsManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 5c28be3..af09bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -25,7 +25,6 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
import android.view.View;
@@ -276,19 +275,11 @@
void userActivity();
- boolean interceptMediaKey(KeyEvent event);
-
- boolean dispatchKeyEventPreIme(KeyEvent event);
-
- boolean onMenuPressed();
-
void endAffordanceLaunch();
/** Should the keyguard be hidden immediately in response to a back press/gesture. */
boolean shouldKeyguardHideImmediately();
- boolean onSpacePressed();
-
void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
Runnable cancelAction);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 6431ef9..2bc7b99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
@@ -33,12 +34,15 @@
import android.os.Vibrator;
import android.util.Log;
import android.util.Slog;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.LetterboxDetails;
@@ -49,6 +53,7 @@
import com.android.systemui.camera.CameraIntents;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSHost;
@@ -107,6 +112,7 @@
private final Lazy<CameraLauncher> mCameraLauncherLazy;
private final QuickSettingsController mQsController;
private final QSHost mQSHost;
+ private final FeatureFlags mFeatureFlags;
private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
@@ -144,7 +150,8 @@
Lazy<CameraLauncher> cameraLauncherLazy,
UserTracker userTracker,
QSHost qsHost,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter,
+ FeatureFlags featureFlags) {
mCentralSurfaces = centralSurfaces;
mQsController = quickSettingsController;
mContext = context;
@@ -171,6 +178,7 @@
mCameraLauncherLazy = cameraLauncherLazy;
mUserTracker = userTracker;
mQSHost = qsHost;
+ mFeatureFlags = featureFlags;
mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
@@ -314,7 +322,7 @@
mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
if (mShadeViewController.isFullyCollapsed()) {
if (mVibrateOnOpening) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ vibrateOnNavigationKeyDown();
}
mShadeViewController.expand(true /* animate */);
mNotificationStackScrollLayoutController.setWillExpand(true);
@@ -587,4 +595,15 @@
}
return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
}
+
+ @VisibleForTesting
+ void vibrateOnNavigationKeyDown() {
+ if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ mShadeViewController.performHapticFeedback(
+ HapticFeedbackConstants.GESTURE_START
+ );
+ } else {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ }
+ }
}
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 127569d..ccb87bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -89,7 +89,6 @@
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -1612,8 +1611,6 @@
mBackActionInteractor.setup(mQsController, mShadeSurface);
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
- mHeadsUpManager.addListener(mCentralSurfacesComponent.getStatusBarHeadsUpChangeListener());
-
// Listen for demo mode changes
mDemoModeController.addCallback(mDemoModeCallback);
@@ -2638,44 +2635,6 @@
}
@Override
- public boolean interceptMediaKey(KeyEvent event) {
- return mState == StatusBarState.KEYGUARD
- && mStatusBarKeyguardViewManager.interceptMediaKey(event);
- }
-
- /**
- * While IME is active and a BACK event is detected, check with
- * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
- * should be handled before routing to IME, in order to prevent the user having to hit back
- * twice to exit bouncer.
- */
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent event) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_BACK:
- if (mState == StatusBarState.KEYGUARD
- && mStatusBarKeyguardViewManager.dispatchBackKeyEventPreIme()) {
- return mBackActionInteractor.onBackRequested();
- }
- }
- return false;
- }
-
- protected boolean shouldUnlockOnMenuPressed() {
- return mDeviceInteractive && mState != StatusBarState.SHADE
- && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
- }
-
- @Override
- public boolean onMenuPressed() {
- if (shouldUnlockOnMenuPressed()) {
- mShadeController.animateCollapseShadeForced();
- return true;
- }
- return false;
- }
-
- @Override
public void endAffordanceLaunch() {
releaseGestureWakeLock();
mCameraLauncherLazy.get().setLaunchingAffordance(false);
@@ -2694,15 +2653,6 @@
return (isScrimmedBouncer || isBouncerOverDream);
}
- @Override
- public boolean onSpacePressed() {
- if (mDeviceInteractive && mState != StatusBarState.SHADE) {
- mShadeController.animateCollapseShadeForced();
- return true;
- }
- return false;
- }
-
private void showBouncerOrLockScreenIfKeyguard() {
// If the keyguard is animating away, we aren't really the keyguard anymore and should not
// show the bouncer/lockscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index 0bf0f4b..d22ed38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -1,3 +1,18 @@
+/*
+ * 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.statusbar.phone;
import android.content.Context;
@@ -43,6 +58,8 @@
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
+import org.jetbrains.annotations.NotNull;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -55,13 +72,13 @@
* normally reserved for notifications.
*/
@SysUISingleton
-public class NotificationIconAreaController implements
+public class LegacyNotificationIconAreaControllerImpl implements
+ NotificationIconAreaController,
DarkReceiver,
StatusBarStateController.StateListener,
NotificationWakeUpCoordinator.WakeUpListener,
DemoMode {
- public static final String HIGH_PRIORITY = "high_priority";
private static final long AOD_ICONS_APPEAR_DURATION = 200;
@ColorInt
private static final int DEFAULT_AOD_ICON_COLOR = 0xffffffff;
@@ -110,7 +127,7 @@
};
@Inject
- public NotificationIconAreaController(
+ public LegacyNotificationIconAreaControllerImpl(
Context context,
StatusBarStateController statusBarStateController,
NotificationWakeUpCoordinator wakeUpCoordinator,
@@ -192,7 +209,7 @@
}
}
- public void onDensityOrFontScaleChanged(Context context) {
+ public void onDensityOrFontScaleChanged(@NotNull Context context) {
updateIconLayoutParams(context);
}
@@ -493,7 +510,7 @@
mNotificationIcons.showIconIsolated(icon, animated);
}
- public void setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate) {
+ public void setIsolatedIconLocation(@NotNull Rect iconDrawingRect, boolean requireStateUpdate) {
mNotificationIcons.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
new file mode 100644
index 0000000..0079f7c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.statusbar.phone
+
+import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import com.android.systemui.statusbar.NotificationShelfController
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.collection.ListEntry
+
+/**
+ * A controller for the space in the status bar to the left of the system icons. This area is
+ * normally reserved for notifications.
+ */
+interface NotificationIconAreaController {
+ /** Called by the Keyguard*ViewController whose view contains the aod icons. */
+ fun setupAodIcons(aodIcons: NotificationIconContainer)
+ fun setupShelf(notificationShelfController: NotificationShelfController)
+ fun setShelfIcons(icons: NotificationIconContainer)
+ fun onDensityOrFontScaleChanged(context: Context)
+
+ /** Returns the view that represents the notification area. */
+ fun getNotificationInnerAreaView(): View?
+
+ /** Updates the notifications with the given list of notifications to display. */
+ fun updateNotificationIcons(entries: List<@JvmSuppressWildcards ListEntry>)
+ fun updateAodNotificationIcons()
+ fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean)
+ fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean)
+ fun setAnimationsEnabled(enabled: Boolean)
+ fun onThemeChanged()
+ fun getHeight(): Int
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt
new file mode 100644
index 0000000..d1ddd51
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.statusbar.phone
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconAreaControllerViewBinderWrapperImpl
+import dagger.Module
+import dagger.Provides
+import javax.inject.Provider
+
+@Module
+object NotificationIconAreaControllerModule {
+ @Provides
+ fun provideNotificationIconAreaControllerImpl(
+ featureFlags: FeatureFlags,
+ legacyProvider: Provider<LegacyNotificationIconAreaControllerImpl>,
+ newProvider: Provider<NotificationIconAreaControllerViewBinderWrapperImpl>,
+ ): NotificationIconAreaController =
+ if (featureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+ newProvider.get()
+ } else {
+ legacyProvider.get()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 931aedd..4de669c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -28,8 +28,7 @@
import com.android.systemui.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.RemoteUserInput
+import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
@@ -56,7 +55,7 @@
private val centralSurfaces: CentralSurfaces,
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
- private val sceneInteractor: Provider<SceneInteractor>,
+ private val windowRootView: Provider<WindowRootView>,
private val shadeLogger: ShadeLogger,
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
private val userChipViewModel: StatusBarUserChipViewModel,
@@ -80,7 +79,8 @@
statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer))
if (moveFromCenterAnimationController == null) return
- val statusBarLeftSide: View = mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
+ val statusBarLeftSide: View =
+ mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
val systemIconArea: ViewGroup = mView.requireViewById(R.id.status_bar_end_side_content)
val viewsToAnimate = arrayOf(
@@ -179,11 +179,8 @@
// If scene framework is enabled, route the touch to it and
// ignore the rest of the gesture.
if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
- sceneInteractor.get()
- .onRemoteUserInput(RemoteUserInput.translateMotionEvent(event))
- // TODO(b/291965119): remove once view is expanded to cover the status bar
- sceneInteractor.get().setVisible(true, "swipe down from status bar")
- return false
+ windowRootView.get().dispatchTouchEvent(event)
+ return true
}
if (event.action == MotionEvent.ACTION_DOWN) {
@@ -247,7 +244,7 @@
private val centralSurfaces: CentralSurfaces,
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
- private val sceneInteractor: Provider<SceneInteractor>,
+ private val windowRootView: Provider<WindowRootView>,
private val shadeLogger: ShadeLogger,
private val viewUtil: ViewUtil,
private val configurationController: ConfigurationController,
@@ -269,7 +266,7 @@
centralSurfaces,
shadeController,
shadeViewController,
- sceneInteractor,
+ windowRootView,
shadeLogger,
statusBarMoveFromCenterAnimationController,
userChipViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index fc66138..62a8cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -709,6 +709,11 @@
}
}
+ public void onUnlockAnimationFinished() {
+ mAnimatingPanelExpansionOnUnlock = false;
+ applyAndDispatchState();
+ }
+
/**
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index 9a295e6..4b39854 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -16,23 +16,24 @@
package com.android.systemui.statusbar.phone;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import javax.inject.Inject;
/**
- * Ties the {@link CentralSurfaces} to {@link com.android.systemui.statusbar.policy.HeadsUpManager}.
+ * Ties the status bar to {@link com.android.systemui.statusbar.policy.HeadsUpManager}.
*/
-@CentralSurfacesComponent.CentralSurfacesScope
-public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener {
+@SysUISingleton
+public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener, CoreStartable {
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final StatusBarWindowController mStatusBarWindowController;
private final ShadeViewController mShadeViewController;
@@ -63,6 +64,11 @@
}
@Override
+ public void start() {
+ mHeadsUpManager.addListener(this);
+ }
+
+ @Override
public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
if (inPinnedMode) {
mNotificationShadeWindowController.setHeadsUpShowing(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
index 5ace226..32e5c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
@@ -24,4 +24,6 @@
KEYGUARD,
/** Quick settings (inside the shade). */
QS,
+ /** ShadeCarrierGroup (above QS status bar in expanded mode). */
+ SHADE_CARRIER_GROUP,
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 7fe01825..a6284e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -32,6 +32,8 @@
import android.view.View;
import android.view.ViewParent;
+import androidx.annotation.Nullable;
+
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -254,16 +256,16 @@
@Override
public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
- boolean appRequestedAuth,
+ boolean appRequestedAuth, @Nullable Integer actionIndex,
NotificationRemoteInputManager.ClickHandler defaultHandler) {
final boolean isActivity = pendingIntent.isActivity();
if (isActivity || appRequestedAuth) {
- mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent);
+ mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent, actionIndex);
final boolean afterKeyguardGone = mActivityIntentHelper
.wouldPendingLaunchResolverActivity(pendingIntent,
mLockscreenUserManager.getCurrentUserId());
mActivityStarter.dismissKeyguardThenExecute(() -> {
- mActionClickLogger.logKeyguardGone(pendingIntent);
+ mActionClickLogger.logKeyguardGone(pendingIntent, actionIndex);
try {
ActivityManager.getService().resumeAppSwitches();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 1bceb29..cd1afc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -223,10 +223,14 @@
}
.setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_SLOW_IN),
true /* animate */)
- interactionJankMonitor.begin(
- notifShadeWindowControllerLazy.get().windowRootView,
- CUJ_SCREEN_OFF_SHOW_AOD
- )
+ val builder = InteractionJankMonitor.Configuration.Builder
+ .withView(
+ InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD,
+ notifShadeWindowControllerLazy.get().windowRootView
+ )
+ .setTag(statusBarStateControllerImpl.getClockId())
+
+ interactionJankMonitor.begin(builder)
}
override fun onStartedWakingUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index 3a3663d..bbbe16f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks;
import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
-import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarterModule;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
@@ -72,11 +71,6 @@
WindowRootView getWindowRootView();
/**
- * Creates a StatusBarHeadsUpChangeListener.
- */
- StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
-
- /**
* Creates a CentralSurfacesCommandQueueCallbacks.
*/
CentralSurfacesCommandQueueCallbacks getCentralSurfacesCommandQueueCallbacks();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
index 6e51ed0..c695773 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
@@ -18,6 +18,9 @@
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.carrier.ShadeCarrierGroup
import javax.inject.Inject
/** All flagging methods related to the new status bar pipeline (see b/238425913). */
@@ -26,11 +29,19 @@
@Inject
constructor(
context: Context,
+ private val featureFlags: FeatureFlags,
) {
private val mobileSlot = context.getString(com.android.internal.R.string.status_bar_mobile)
private val wifiSlot = context.getString(com.android.internal.R.string.status_bar_wifi)
/**
+ * True if we should display the mobile icons in the [ShadeCarrierGroup] using the new status
+ * bar Data pipeline.
+ */
+ fun useNewShadeCarrierGroupMobileIcons(): Boolean =
+ featureFlags.isEnabled(Flags.NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS)
+
+ /**
* For convenience in the StatusBarIconController, we want to gate some actions based on slot
* name and the flag together.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
index 78231e2..99ed2d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
@@ -60,6 +60,19 @@
}
}
+ /** This name has been derived from SubscriptionModel. see [SubscriptionModel] */
+ data class SubscriptionDerived(override val name: String) : NetworkNameModel {
+ override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
+ if (prevVal !is SubscriptionDerived || prevVal.name != name) {
+ row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+ }
+ }
+
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+ }
+ }
+
/**
* This name has been derived from the sim via
* [android.telephony.TelephonyManager.getSimOperatorName].
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 16c4027..27f6df4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -34,4 +34,7 @@
/** Subscriptions in the same group may be filtered or treated as a single subscription */
val groupUuid: ParcelUuid? = null,
+
+ /** Text representing the name for this connection */
+ val carrierName: String,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index c1af6df..a89b1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -115,10 +115,18 @@
*/
val cdmaRoaming: StateFlow<Boolean>
- /** The service provider name for this network connection, or the default name */
+ /** The service provider name for this network connection, or the default name. */
val networkName: StateFlow<NetworkNameModel>
/**
+ * The service provider name for this network connection, or the default name.
+ *
+ * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+ * provided is identical
+ */
+ val carrierName: StateFlow<NetworkNameModel>
+
+ /**
* True if this type of connection is allowed while airplane mode is on, and false otherwise.
*/
val isAllowedDuringAirplaneMode: StateFlow<Boolean>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index 17d20c2..c576b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -184,7 +184,10 @@
override val cdmaRoaming = MutableStateFlow(false)
- override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+ override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived(DEMO_CARRIER_NAME))
+
+ override val carrierName =
+ MutableStateFlow(NetworkNameModel.SubscriptionDerived(DEMO_CARRIER_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
@@ -200,6 +203,7 @@
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(event.name)
+ carrierName.value = NetworkNameModel.SubscriptionDerived("${event.name} ${event.subId}")
_carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
@@ -227,6 +231,7 @@
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+ carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)
// TODO(b/276943904): is carrierId a thing with carrier merged networks?
_carrierId.value = INVALID_SUBSCRIPTION_ID
numberOfLevels.value = event.numberOfLevels
@@ -248,6 +253,7 @@
}
companion object {
+ private const val DEMO_CARRIER_NAME = "Demo Carrier"
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}
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 0e4ceeb..ee13d93 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
@@ -92,9 +92,12 @@
private fun maybeCreateSubscription(subId: Int) {
if (!subscriptionInfoCache.containsKey(subId)) {
- SubscriptionModel(subscriptionId = subId, isOpportunistic = false).also {
- subscriptionInfoCache[subId] = it
- }
+ SubscriptionModel(
+ subscriptionId = subId,
+ isOpportunistic = false,
+ carrierName = DEFAULT_CARRIER_NAME,
+ )
+ .also { subscriptionInfoCache[subId] = it }
_subscriptions.value = subscriptionInfoCache.values.toList()
}
@@ -327,6 +330,7 @@
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
+ private const val DEFAULT_CARRIER_NAME = "demo carrier"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index 65f4866..28be3be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -108,6 +108,8 @@
NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
)
+ override val carrierName: StateFlow<NetworkNameModel> = networkName
+
override val numberOfLevels: StateFlow<Int> =
wifiRepository.wifiNetwork
.map {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 8ba7d21..ee11c06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -22,6 +22,7 @@
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -47,6 +48,7 @@
override val subId: Int,
startingIsCarrierMerged: Boolean,
override val tableLogBuffer: TableLogBuffer,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
private val defaultNetworkName: NetworkNameModel,
private val networkNameSeparator: String,
@Application scope: CoroutineScope,
@@ -80,6 +82,7 @@
mobileRepoFactory.build(
subId,
tableLogBuffer,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
)
@@ -287,6 +290,16 @@
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
+ override val carrierName =
+ activeRepo
+ .flatMapLatest { it.carrierName }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ initialValue = activeRepo.value.carrierName.value,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
+
override val isAllowedDuringAirplaneMode =
activeRepo
.flatMapLatest { it.isAllowedDuringAirplaneMode }
@@ -307,6 +320,7 @@
fun build(
subId: Int,
startingIsCarrierMerged: Boolean,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): FullMobileConnectionRepository {
@@ -317,6 +331,7 @@
subId,
startingIsCarrierMerged,
mobileLogger,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
scope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index aadc975..1f1ac92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -43,6 +43,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
@@ -80,6 +81,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
override val subId: Int,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
private val telephonyManager: TelephonyManager,
@@ -281,6 +283,14 @@
}
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+ override val carrierName =
+ subscriptionModel
+ .map {
+ it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
+ ?: defaultNetworkName
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+
/**
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
* internal state where callbacks aren't provided. Any of those events should be merged into
@@ -350,11 +360,13 @@
fun build(
subId: Int,
mobileLogger: TableLogBuffer,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
subId,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
telephonyManager.createForSubscriptionId(subId),
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 54948a4..67b04db 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
@@ -319,10 +319,17 @@
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
+ private fun subscriptionModelForSubId(subId: Int): StateFlow<SubscriptionModel?> {
+ return subscriptions
+ .map { list -> list.firstOrNull { model -> model.subscriptionId == subId } }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+ }
+
private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
return fullMobileRepoFactory.build(
subId,
isCarrierMerged(subId),
+ subscriptionModelForSubId(subId),
defaultNetworkName,
networkNameSeparator,
)
@@ -373,6 +380,7 @@
subscriptionId = subscriptionId,
isOpportunistic = isOpportunistic,
groupUuid = groupUuid,
+ carrierName = carrierName.toString(),
)
companion object {
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 1a13827..4cfde5b 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
@@ -92,6 +92,22 @@
*/
val networkName: StateFlow<NetworkNameModel>
+ /**
+ * Provider name for this network connection. The name can be one of 3 values:
+ * 1. The default network name, if one is configured
+ * 2. A name provided by the [SubscriptionModel] of this network connection
+ * 3. Or, in the case where the repository sends us the default network name, we check for an
+ * override in [connectionInfo.operatorAlphaShort], a value that is derived from
+ * [ServiceState]
+ *
+ * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+ * provided is identical
+ */
+ val carrierName: StateFlow<String>
+
+ /** True if there is only one active subscription. */
+ val isSingleCarrier: StateFlow<Boolean>
+
/** True if this line of service is emergency-only */
val isEmergencyOnly: StateFlow<Boolean>
@@ -126,6 +142,7 @@
defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
override val alwaysShowDataRatIcon: StateFlow<Boolean>,
override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+ override val isSingleCarrier: StateFlow<Boolean>,
override val mobileIsDefault: StateFlow<Boolean>,
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
@@ -171,6 +188,22 @@
connectionRepository.networkName.value
)
+ override val carrierName =
+ combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
+ operatorAlphaShort,
+ networkName ->
+ if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+ operatorAlphaShort
+ } else {
+ networkName.name
+ }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ connectionRepository.carrierName.value.name
+ )
+
/** What the mobile icon would be before carrierId overrides */
private val defaultNetworkType: StateFlow<MobileIconGroup> =
combine(
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 e90f40c7..d08808b 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
@@ -76,6 +76,9 @@
/** True if the CDMA level should be preferred over the primary level. */
val alwaysUseCdmaLevel: StateFlow<Boolean>
+ /** True if there is only one active subscription. */
+ val isSingleCarrier: StateFlow<Boolean>
+
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
@@ -252,6 +255,17 @@
.mapLatest { it.alwaysShowCdmaRssi }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override val isSingleCarrier: StateFlow<Boolean> =
+ mobileConnectionsRepo.subscriptions
+ .map { it.size == 1 }
+ .logDiffsForTable(
+ tableLogger,
+ columnPrefix = LOGGING_PREFIX,
+ columnName = "isSingleCarrier",
+ initialValue = false,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
@@ -298,6 +312,7 @@
activeDataConnectionHasDataEnabled,
alwaysShowDataRatIcon,
alwaysUseCdmaLevel,
+ isSingleCarrier,
mobileIsDefault,
defaultMobileIconMapping,
defaultMobileIconGroup,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index d7fcf48..02e50a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -19,6 +19,7 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.carrier.ShadeCarrierGroupController
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
@@ -49,6 +50,8 @@
private var isCollecting: Boolean = false
private var lastValue: List<Int>? = null
+ private var shadeCarrierGroupController: ShadeCarrierGroupController? = null
+
override fun start() {
// Start notifying the icon controller of subscriptions
scope.launch {
@@ -57,10 +60,16 @@
logger.logUiAdapterSubIdsSentToIconController(it)
lastValue = it
iconController.setNewMobileIconSubIds(it)
+ shadeCarrierGroupController?.updateModernMobileIcons(it)
}
}
}
+ /** Set the [ShadeCarrierGroupController] to notify of subscription updates */
+ fun setShadeCarrierGroupController(controller: ShadeCarrierGroupController) {
+ shadeCarrierGroupController = controller
+ }
+
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("isCollecting=$isCollecting")
pw.println("Last values sent to icon controller: $lastValue")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index cea6654..2af6795b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -57,7 +57,7 @@
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
@@ -71,7 +71,7 @@
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
@@ -85,7 +85,7 @@
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 55bc8d5..4b2fb43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -50,6 +50,7 @@
fun bind(
view: ViewGroup,
viewModel: LocationBasedMobileViewModel,
+ @StatusBarIconView.VisibleState initialVisibilityState: Int = STATE_HIDDEN,
logger: MobileViewLogger,
): ModernStatusBarViewBinding {
val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
@@ -68,12 +69,12 @@
// TODO(b/238425913): We should log this visibility state.
@StatusBarIconView.VisibleState
- val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+ val visibilityState: MutableStateFlow<Int> = MutableStateFlow(initialVisibilityState)
val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
- var isCollecting: Boolean = false
+ var isCollecting = false
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
new file mode 100644
index 0000000..081e101
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.statusbar.pipeline.mobile.ui.binder
+
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+import kotlinx.coroutines.launch
+
+object ShadeCarrierBinder {
+ /** Binds the view to the view-model, continuing to update the former based on the latter */
+ @JvmStatic
+ fun bind(
+ carrierTextView: AutoMarqueeTextView,
+ viewModel: ShadeCarrierGroupMobileIconViewModel,
+ ) {
+ carrierTextView.isVisible = true
+
+ carrierTextView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch { viewModel.carrierName.collect { carrierTextView.text = it } }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
new file mode 100644
index 0000000..f407127
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.statusbar.pipeline.mobile.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.ShadeCarrierBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+
+/**
+ * ViewGroup containing a mobile carrier name and icon in the Shade Header. Can be multiple
+ * instances as children under [ShadeCarrierGroup]
+ */
+class ModernShadeCarrierGroupMobileView(
+ context: Context,
+ attrs: AttributeSet?,
+) : LinearLayout(context, attrs) {
+
+ var subId: Int = -1
+
+ override fun toString(): String {
+ return "ModernShadeCarrierGroupMobileView(" +
+ "subId=$subId, " +
+ "viewString=${super.toString()}"
+ }
+
+ companion object {
+
+ /**
+ * Inflates a new instance of [ModernShadeCarrierGroupMobileView], binds it to [viewModel],
+ * and returns it.
+ */
+ @JvmStatic
+ fun constructAndBind(
+ context: Context,
+ logger: MobileViewLogger,
+ slot: String,
+ viewModel: ShadeCarrierGroupMobileIconViewModel,
+ ): ModernShadeCarrierGroupMobileView {
+ return (LayoutInflater.from(context).inflate(R.layout.shade_carrier_new, null)
+ as ModernShadeCarrierGroupMobileView)
+ .also {
+ it.subId = viewModel.subscriptionId
+
+ val iconView = it.requireViewById<ModernStatusBarMobileView>(R.id.mobile_combo)
+ iconView.initView(slot) {
+ MobileIconBinder.bind(iconView, viewModel, STATE_ICON, logger)
+ }
+ logger.logNewViewBinding(it, viewModel)
+
+ val textView = it.requireViewById<AutoMarqueeTextView>(R.id.mobile_carrier_text)
+ ShadeCarrierBinder.bind(textView, viewModel)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index 4144293d..68d02de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -60,7 +60,9 @@
as ModernStatusBarMobileView)
.also {
it.subId = viewModel.subscriptionId
- it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) }
+ it.initView(slot) {
+ MobileIconBinder.bind(view = it, viewModel = viewModel, logger = logger)
+ }
logger.logNewViewBinding(it, viewModel)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
index a51982c..e7c311d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
@@ -18,7 +18,13 @@
import android.graphics.Color
import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
/**
* A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
@@ -26,12 +32,12 @@
*
* @param commonImpl for convenience, this class wraps a base interface that can provides all of the
* common implementations between locations. See [MobileIconViewModel]
- * @property locationName the name of the location of this VM, used for logging.
+ * @property location the [StatusBarLocation] of this VM.
* @property verboseLogger an optional logger to log extremely verbose view updates.
*/
abstract class LocationBasedMobileViewModel(
val commonImpl: MobileIconViewModelCommon,
- val locationName: String,
+ val location: StatusBarLocation,
val verboseLogger: VerboseMobileViewLogger?,
) : MobileIconViewModelCommon by commonImpl {
val defaultColor: Int = Color.WHITE
@@ -39,10 +45,12 @@
companion object {
fun viewModelForLocation(
commonImpl: MobileIconViewModelCommon,
+ interactor: MobileIconInteractor,
verboseMobileViewLogger: VerboseMobileViewLogger,
- loc: StatusBarLocation,
+ location: StatusBarLocation,
+ scope: CoroutineScope,
): LocationBasedMobileViewModel =
- when (loc) {
+ when (location) {
StatusBarLocation.HOME ->
HomeMobileIconViewModel(
commonImpl,
@@ -50,6 +58,12 @@
)
StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl)
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl)
+ StatusBarLocation.SHADE_CARRIER_GROUP ->
+ ShadeCarrierGroupMobileIconViewModel(
+ commonImpl,
+ interactor,
+ scope,
+ )
}
}
}
@@ -61,7 +75,7 @@
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "Home",
+ location = StatusBarLocation.HOME,
verboseMobileViewLogger,
)
@@ -71,18 +85,40 @@
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "QS",
+ location = StatusBarLocation.QS,
// Only do verbose logging for the Home location.
verboseLogger = null,
)
+class ShadeCarrierGroupMobileIconViewModel(
+ commonImpl: MobileIconViewModelCommon,
+ interactor: MobileIconInteractor,
+ scope: CoroutineScope,
+) :
+ MobileIconViewModelCommon,
+ LocationBasedMobileViewModel(
+ commonImpl,
+ location = StatusBarLocation.SHADE_CARRIER_GROUP,
+ // Only do verbose logging for the Home location.
+ verboseLogger = null,
+ ) {
+ private val isSingleCarrier = interactor.isSingleCarrier
+ val carrierName = interactor.carrierName
+
+ override val isVisible: StateFlow<Boolean> =
+ combine(super.isVisible, isSingleCarrier) { isVisible, isSingleCarrier ->
+ if (isSingleCarrier) false else isVisible
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), super.isVisible.value)
+}
+
class KeyguardMobileIconViewModel(
commonImpl: MobileIconViewModelCommon,
) :
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "Keyguard",
+ location = StatusBarLocation.KEYGUARD,
// Only do verbose logging for the Home location.
verboseLogger = null,
)
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 fe24815..275cfc5 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
@@ -221,36 +221,15 @@
override val activityInVisible: Flow<Boolean> =
activity
.map { it?.hasActivityIn ?: false }
- .distinctUntilChanged()
- .logDiffsForTable(
- iconInteractor.tableLogBuffer,
- columnPrefix = "",
- columnName = "activityInVisible",
- initialValue = false,
- )
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val activityOutVisible: Flow<Boolean> =
activity
.map { it?.hasActivityOut ?: false }
- .distinctUntilChanged()
- .logDiffsForTable(
- iconInteractor.tableLogBuffer,
- columnPrefix = "",
- columnName = "activityOutVisible",
- initialValue = false,
- )
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val activityContainerVisible: Flow<Boolean> =
activity
.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
- .distinctUntilChanged()
- .logDiffsForTable(
- iconInteractor.tableLogBuffer,
- columnPrefix = "",
- columnName = "activityContainerVisible",
- initialValue = false,
- )
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 5cf887e..216afb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -22,6 +22,7 @@
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
@@ -58,6 +59,8 @@
private val statusBarPipelineFlags: StatusBarPipelineFlags,
) {
@VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
+ @VisibleForTesting
+ val mobileIconInteractorSubIdCache = mutableMapOf<Int, MobileIconInteractor>()
val subscriptionIdsFlow: StateFlow<List<Int>> =
interactor.filteredSubscriptions
@@ -91,15 +94,17 @@
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
init {
- scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } }
+ scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
}
fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
val common = commonViewModelForSub(subId)
return LocationBasedMobileViewModel.viewModelForLocation(
common,
+ mobileIconInteractorForSub(subId),
verboseLogger,
location,
+ scope,
)
}
@@ -107,7 +112,7 @@
return mobileIconSubIdCache[subId]
?: MobileIconViewModel(
subId,
- interactor.createMobileConnectionInteractorForSubId(subId),
+ mobileIconInteractorForSub(subId),
airplaneModeInteractor,
constants,
scope,
@@ -115,8 +120,20 @@
.also { mobileIconSubIdCache[subId] = it }
}
- private fun removeInvalidModelsFromCache(subIds: List<Int>) {
+ @VisibleForTesting
+ fun mobileIconInteractorForSub(subId: Int): MobileIconInteractor {
+ return mobileIconInteractorSubIdCache[subId]
+ ?: interactor.createMobileConnectionInteractorForSubId(subId).also {
+ mobileIconInteractorSubIdCache[subId] = it
+ }
+ }
+
+ private fun invalidateCaches(subIds: List<Int>) {
val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
+
+ mobileIconInteractorSubIdCache.keys
+ .filter { !subIds.contains(it) }
+ .forEach { subId -> mobileIconInteractorSubIdCache.remove(subId) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
index cd5b92c..00bd616 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
@@ -18,6 +18,7 @@
import android.graphics.Color
import com.android.systemui.statusbar.phone.StatusBarLocation
+import java.lang.IllegalArgumentException
/**
* A view model for a wifi icon in a specific location. This allows us to control parameters that
@@ -43,6 +44,8 @@
StatusBarLocation.HOME -> HomeWifiViewModel(commonImpl)
StatusBarLocation.KEYGUARD -> KeyguardWifiViewModel(commonImpl)
StatusBarLocation.QS -> QsWifiViewModel(commonImpl)
+ StatusBarLocation.SHADE_CARRIER_GROUP ->
+ throw IllegalArgumentException("invalid location for WifiViewModel: $location")
}
}
}
@@ -64,3 +67,11 @@
class QsWifiViewModel(
commonImpl: WifiViewModelCommon,
) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
+
+/**
+ * A view model for the wifi icon in the shade carrier group (visible when quick settings is fully
+ * expanded, and in large screen shade). Currently unused.
+ */
+class ShadeCarrierGroupWifiViewModel(
+ commonImpl: WifiViewModelCommon,
+) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index d39a53d..9cc3cdb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -44,6 +44,7 @@
import android.media.session.MediaSession.Token;
import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -57,6 +58,7 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager;
+import androidx.annotation.NonNull;
import androidx.lifecycle.Observer;
import com.android.internal.annotations.GuardedBy;
@@ -81,6 +83,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
@@ -131,7 +134,7 @@
private final Receiver mReceiver = new Receiver();
private final RingerModeObservers mRingerModeObservers;
private final MediaSessions mMediaSessions;
- private final CaptioningManager mCaptioningManager;
+ private final AtomicReference<CaptioningManager> mCaptioningManager = new AtomicReference<>();
private final KeyguardManager mKeyguardManager;
private final ActivityManager mActivityManager;
private final UserTracker mUserTracker;
@@ -155,16 +158,16 @@
private final WakefulnessLifecycle.Observer mWakefullnessLifecycleObserver =
new WakefulnessLifecycle.Observer() {
- @Override
- public void onStartedWakingUp() {
- mDeviceInteractive = true;
- }
+ @Override
+ public void onStartedWakingUp() {
+ mDeviceInteractive = true;
+ }
- @Override
- public void onFinishedGoingToSleep() {
- mDeviceInteractive = false;
- }
- };
+ @Override
+ public void onFinishedGoingToSleep() {
+ mDeviceInteractive = false;
+ }
+ };
@Inject
public VolumeDialogControllerImpl(
@@ -179,7 +182,6 @@
AccessibilityManager accessibilityManager,
PackageManager packageManager,
WakefulnessLifecycle wakefulnessLifecycle,
- CaptioningManager captioningManager,
KeyguardManager keyguardManager,
ActivityManager activityManager,
UserTracker userTracker,
@@ -209,17 +211,19 @@
mVibrator = vibrator;
mHasVibrator = mVibrator.hasVibrator();
mAudioService = iAudioService;
- mCaptioningManager = captioningManager;
mKeyguardManager = keyguardManager;
mActivityManager = activityManager;
mUserTracker = userTracker;
+ mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mWorker));
+ createCaptioningManagerServiceByUserContext(mUserTracker.getUserContext());
+
dumpManager.registerDumpable("VolumeDialogControllerImpl", this);
boolean accessibilityVolumeStreamActive = accessibilityManager
.isAccessibilityVolumeStreamActive();
mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
- VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
- VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+ VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
+ VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver);
}
@@ -316,12 +320,31 @@
mWorker.sendEmptyMessage(W.GET_STATE);
}
- public boolean areCaptionsEnabled() {
- return mCaptioningManager.isSystemAudioCaptioningEnabled();
+ /**
+ * We met issues about the wrong state of System Caption in multi-user mode.
+ * It happened in the usage of CaptioningManager Service from SysUI process
+ * that is a global system process of User 0.
+ * Therefore, we have to add callback on UserTracker that allows us to get the Context of
+ * active User and then get the corresponding CaptioningManager Service for further usages.
+ */
+ private final UserTracker.Callback mUserChangedCallback =
+ new UserTracker.Callback() {
+ @Override
+ public void onUserChanged(int newUser, @NonNull Context userContext) {
+ createCaptioningManagerServiceByUserContext(userContext);
+ }
+ };
+
+ private void createCaptioningManagerServiceByUserContext(@NonNull Context userContext) {
+ mCaptioningManager.set(userContext.getSystemService(CaptioningManager.class));
}
- public void setCaptionsEnabled(boolean isEnabled) {
- mCaptioningManager.setSystemAudioCaptioningEnabled(isEnabled);
+ public void getCaptionsEnabledState(boolean checkForSwitchState) {
+ mWorker.obtainMessage(W.GET_CAPTIONS_ENABLED_STATE, checkForSwitchState).sendToTarget();
+ }
+
+ public void setCaptionsEnabledState(boolean enabled) {
+ mWorker.obtainMessage(W.SET_CAPTIONS_ENABLED_STATE, enabled).sendToTarget();
}
public void getCaptionsComponentState(boolean fromTooltip) {
@@ -362,8 +385,8 @@
}
public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
- mShowVolumeDialog = volumeUi;
- mShowSafetyWarning = safetyWarning;
+ mShowVolumeDialog = volumeUi;
+ mShowSafetyWarning = safetyWarning;
}
@Override
@@ -414,12 +437,38 @@
}
private void onShowCsdWarningW(@AudioManager.CsdWarning int csdWarning, int durationMs) {
- mCallbacks.onShowCsdWarning(csdWarning, durationMs);
+ mCallbacks.onShowCsdWarning(csdWarning, durationMs);
}
private void onGetCaptionsComponentStateW(boolean fromTooltip) {
- mCallbacks.onCaptionComponentStateChanged(
- mCaptioningManager.isSystemAudioCaptioningUiEnabled(), fromTooltip);
+ CaptioningManager captioningManager = mCaptioningManager.get();
+ if (null != captioningManager) {
+ mCallbacks.onCaptionComponentStateChanged(
+ captioningManager.isSystemAudioCaptioningUiEnabled(), fromTooltip);
+ } else {
+ Log.e(TAG, "onGetCaptionsComponentStateW(), null captioningManager");
+ }
+ }
+
+ private void onGetCaptionsEnabledStateW(boolean checkForSwitchState) {
+ CaptioningManager captioningManager = mCaptioningManager.get();
+ if (null != captioningManager) {
+ mCallbacks.onCaptionEnabledStateChanged(
+ captioningManager.isSystemAudioCaptioningEnabled(), checkForSwitchState);
+ } else {
+ Log.e(TAG, "onGetCaptionsEnabledStateW(), null captioningManager");
+ }
+ }
+
+ private void onSetCaptionsEnabledStateW(boolean enabled) {
+ CaptioningManager captioningManager = mCaptioningManager.get();
+ if (null != captioningManager) {
+ captioningManager.setSystemAudioCaptioningEnabled(enabled);
+ mCallbacks.onCaptionEnabledStateChanged(
+ captioningManager.isSystemAudioCaptioningEnabled(), false);
+ } else {
+ Log.e(TAG, "onGetCaptionsEnabledStateW(), null captioningManager");
+ }
}
private void onAccessibilityModeChanged(Boolean showA11yStream) {
@@ -719,7 +768,7 @@
* This method will never be called if the CSD (Computed Sound Dose) feature is
* not enabled. See com.android.android.server.audio.SoundDoseHelper for the state of
* the feature.
- * @param warning the type of warning to display, values are one of
+ * @param csdWarning the type of warning to display, values are one of
* {@link android.media.AudioManager#CSD_WARNING_DOSE_REACHED_1X},
* {@link android.media.AudioManager#CSD_WARNING_DOSE_REPEATED_5X},
* {@link android.media.AudioManager#CSD_WARNING_MOMENTARY_EXPOSURE},
@@ -798,6 +847,8 @@
private static final int ACCESSIBILITY_MODE_CHANGED = 15;
private static final int GET_CAPTIONS_COMPONENT_STATE = 16;
private static final int SHOW_CSD_WARNING = 17;
+ private static final int GET_CAPTIONS_ENABLED_STATE = 18;
+ private static final int SET_CAPTIONS_ENABLED_STATE = 19;
W(Looper looper) {
super(looper);
@@ -825,6 +876,10 @@
case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
break;
case SHOW_CSD_WARNING: onShowCsdWarningW(msg.arg1, msg.arg2); break;
+ case GET_CAPTIONS_ENABLED_STATE:
+ onGetCaptionsEnabledStateW((Boolean) msg.obj); break;
+ case SET_CAPTIONS_ENABLED_STATE:
+ onSetCaptionsEnabledStateW((Boolean) msg.obj); break;
}
}
}
@@ -993,6 +1048,17 @@
componentEnabled, fromTooltip));
}
}
+
+ @Override
+ public void onCaptionEnabledStateChanged(Boolean isEnabled, Boolean checkBeforeSwitch) {
+ boolean captionsEnabled = isEnabled != null && isEnabled;
+ for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+ entry.getValue().post(
+ () -> entry.getKey().onCaptionEnabledStateChanged(
+ captionsEnabled, checkBeforeSwitch));
+ }
+ }
+
}
private final class RingerModeObservers {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 6219e4d..aafa16f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1333,21 +1333,30 @@
if (!isServiceComponentEnabled) return;
- updateCaptionsIcon();
+ checkEnabledStateForCaptionsIconUpdate();
if (fromTooltip) showCaptionsTooltip();
}
- private void updateCaptionsIcon() {
- boolean captionsEnabled = mController.areCaptionsEnabled();
- if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) {
- mHandler.post(mODICaptionsIcon.setCaptionsEnabled(captionsEnabled));
+ private void updateCaptionsEnabledH(boolean isCaptionsEnabled, boolean checkForSwitchState) {
+ if (checkForSwitchState) {
+ mController.setCaptionsEnabledState(!isCaptionsEnabled);
+ } else {
+ updateCaptionsIcon(isCaptionsEnabled);
+ }
+ }
+
+ private void checkEnabledStateForCaptionsIconUpdate() {
+ mController.getCaptionsEnabledState(false);
+ }
+
+ private void updateCaptionsIcon(boolean isCaptionsEnabled) {
+ if (mODICaptionsIcon.getCaptionsEnabled() != isCaptionsEnabled) {
+ mHandler.post(mODICaptionsIcon.setCaptionsEnabled(isCaptionsEnabled));
}
}
private void onCaptionIconClicked() {
- boolean isEnabled = mController.areCaptionsEnabled();
- mController.setCaptionsEnabled(!isEnabled);
- updateCaptionsIcon();
+ mController.getCaptionsEnabledState(true);
}
private void incrementManualToggleCount() {
@@ -2363,7 +2372,6 @@
} else {
updateRowsH(activeRow);
}
-
}
@Override
@@ -2371,6 +2379,11 @@
Boolean isComponentEnabled, Boolean fromTooltip) {
updateODICaptionsH(isComponentEnabled, fromTooltip);
}
+
+ @Override
+ public void onCaptionEnabledStateChanged(Boolean isEnabled, Boolean checkForSwitchState) {
+ updateCaptionsEnabledH(isEnabled, checkForSwitchState);
+ }
};
@VisibleForTesting void onPostureChanged(int posture) {
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 316b54e..091a54f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -109,6 +109,7 @@
private WallpaperManager mWallpaperManager;
private final WallpaperLocalColorExtractor mWallpaperLocalColorExtractor;
private SurfaceHolder mSurfaceHolder;
+ private boolean mDrawn = false;
@VisibleForTesting
static final int MIN_SURFACE_WIDTH = 128;
@VisibleForTesting
@@ -238,6 +239,7 @@
private void drawFrameSynchronized() {
synchronized (mLock) {
+ if (mDrawn) return;
drawFrameInternal();
}
}
@@ -275,6 +277,7 @@
Rect dest = mSurfaceHolder.getSurfaceFrame();
try {
canvas.drawBitmap(bitmap, null, dest, null);
+ mDrawn = true;
} finally {
surface.unlockCanvasAndPost(canvas);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index 677d3ff..c894d91 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -180,8 +180,9 @@
}
@Test
- public void testResume() {
- mKeyguardAbsKeyInputViewController.onResume(KeyguardSecurityView.VIEW_REVEALED);
+ public void testOnViewAttached() {
+ reset(mLockPatternUtils);
+ mKeyguardAbsKeyInputViewController.onViewAttached();
verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt());
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
index b349696..438f0f4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
@@ -18,6 +18,8 @@
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static com.android.systemui.flags.Flags.ENABLE_CLOCK_KEYGUARD_PRESENTATION;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -37,6 +39,7 @@
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -59,8 +62,13 @@
@Mock
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@Mock
+ private ConnectedDisplayKeyguardPresentation.Factory
+ mConnectedDisplayKeyguardPresentationFactory;
+ @Mock
private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation;
@Mock
+ private ConnectedDisplayKeyguardPresentation mConnectedDisplayKeyguardPresentation;
+ @Mock
private KeyguardDisplayManager.DeviceStateHelper mDeviceStateHelper;
@Mock
private KeyguardStateController mKeyguardStateController;
@@ -69,7 +77,7 @@
private Executor mBackgroundExecutor = Runnable::run;
private KeyguardDisplayManager mManager;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
-
+ private FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
// The default and secondary displays are both in the default group
private Display mDefaultDisplay;
private Display mSecondaryDisplay;
@@ -80,10 +88,14 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mFakeFeatureFlags.set(ENABLE_CLOCK_KEYGUARD_PRESENTATION, false);
mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController,
mKeyguardStatusViewComponentFactory, mDisplayTracker, mMainExecutor,
- mBackgroundExecutor, mDeviceStateHelper, mKeyguardStateController));
+ mBackgroundExecutor, mDeviceStateHelper, mKeyguardStateController,
+ mConnectedDisplayKeyguardPresentationFactory, mFakeFeatureFlags));
doReturn(mKeyguardPresentation).when(mManager).createPresentation(any());
+ doReturn(mConnectedDisplayKeyguardPresentation).when(
+ mConnectedDisplayKeyguardPresentationFactory).create(any());
mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -138,4 +150,15 @@
when(mKeyguardStateController.isOccluded()).thenReturn(true);
verify(mManager, never()).createPresentation(eq(mSecondaryDisplay));
}
+
+ @Test
+ public void testShow_withClockPresentationFlagEnabled_presentationCreated() {
+ when(mManager.createPresentation(any())).thenCallRealMethod();
+ mFakeFeatureFlags.set(ENABLE_CLOCK_KEYGUARD_PRESENTATION, true);
+ mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay, mSecondaryDisplay});
+
+ mManager.show();
+
+ verify(mConnectedDisplayKeyguardPresentationFactory).create(eq(mSecondaryDisplay));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index 1a9260c..3a94730 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -20,6 +20,7 @@
import android.testing.TestableLooper
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
+import android.widget.ImageView
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.internal.widget.LockPatternUtils
@@ -29,6 +30,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,6 +38,7 @@
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
@@ -45,104 +48,109 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardPasswordViewControllerTest : SysuiTestCase() {
- @Mock private lateinit var keyguardPasswordView: KeyguardPasswordView
- @Mock private lateinit var passwordEntry: EditText
- @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock lateinit var securityMode: KeyguardSecurityModel.SecurityMode
- @Mock lateinit var lockPatternUtils: LockPatternUtils
- @Mock lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
- @Mock lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
- @Mock lateinit var latencyTracker: LatencyTracker
- @Mock lateinit var inputMethodManager: InputMethodManager
- @Mock lateinit var emergencyButtonController: EmergencyButtonController
- @Mock lateinit var mainExecutor: DelayableExecutor
- @Mock lateinit var falsingCollector: FalsingCollector
- @Mock lateinit var keyguardViewController: KeyguardViewController
- @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
- @Mock
- private lateinit var mKeyguardMessageAreaController:
- KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+ @Mock private lateinit var keyguardPasswordView: KeyguardPasswordView
+ @Mock private lateinit var passwordEntry: EditText
+ @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock lateinit var securityMode: KeyguardSecurityModel.SecurityMode
+ @Mock lateinit var lockPatternUtils: LockPatternUtils
+ @Mock lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
+ @Mock lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock lateinit var latencyTracker: LatencyTracker
+ @Mock lateinit var inputMethodManager: InputMethodManager
+ @Mock lateinit var emergencyButtonController: EmergencyButtonController
+ @Mock lateinit var mainExecutor: DelayableExecutor
+ @Mock lateinit var falsingCollector: FalsingCollector
+ @Mock lateinit var keyguardViewController: KeyguardViewController
+ @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
+ @Mock
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
- private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
+ private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- Mockito.`when`(
- keyguardPasswordView.requireViewById<BouncerKeyguardMessageArea>(
- R.id.bouncer_message_area))
- .thenReturn(mKeyguardMessageArea)
- Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
- .thenReturn(mKeyguardMessageAreaController)
- Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry)
- Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry))
- .thenReturn(passwordEntry)
- `when`(keyguardPasswordView.resources).thenReturn(context.resources)
- val fakeFeatureFlags = FakeFeatureFlags()
- fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
- keyguardPasswordViewController =
- KeyguardPasswordViewController(
- keyguardPasswordView,
- keyguardUpdateMonitor,
- securityMode,
- lockPatternUtils,
- keyguardSecurityCallback,
- messageAreaControllerFactory,
- latencyTracker,
- inputMethodManager,
- emergencyButtonController,
- mainExecutor,
- mContext.resources,
- falsingCollector,
- keyguardViewController,
- fakeFeatureFlags)
- }
-
- @Test
- fun testFocusWhenBouncerIsShown() {
- Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true)
- Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
- keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
- keyguardPasswordView.post {
- verify(keyguardPasswordView).requestFocus()
- verify(keyguardPasswordView).showKeyboard()
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ Mockito.`when`(
+ keyguardPasswordView.requireViewById<BouncerKeyguardMessageArea>(
+ R.id.bouncer_message_area
+ )
+ )
+ .thenReturn(mKeyguardMessageArea)
+ Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
+ .thenReturn(mKeyguardMessageAreaController)
+ Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry)
+ Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry))
+ .thenReturn(passwordEntry)
+ whenever(keyguardPasswordView.findViewById<ImageView>(R.id.switch_ime_button))
+ .thenReturn(mock(ImageView::class.java))
+ `when`(keyguardPasswordView.resources).thenReturn(context.resources)
+ val fakeFeatureFlags = FakeFeatureFlags()
+ fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
+ keyguardPasswordViewController =
+ KeyguardPasswordViewController(
+ keyguardPasswordView,
+ keyguardUpdateMonitor,
+ securityMode,
+ lockPatternUtils,
+ keyguardSecurityCallback,
+ messageAreaControllerFactory,
+ latencyTracker,
+ inputMethodManager,
+ emergencyButtonController,
+ mainExecutor,
+ mContext.resources,
+ falsingCollector,
+ keyguardViewController,
+ fakeFeatureFlags
+ )
}
- }
- @Test
- fun testDoNotFocusWhenBouncerIsHidden() {
- Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false)
- Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
- keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
- verify(keyguardPasswordView, never()).requestFocus()
- }
-
- @Test
- fun testHideKeyboardWhenOnPause() {
- keyguardPasswordViewController.onPause()
- keyguardPasswordView.post {
- verify(keyguardPasswordView).clearFocus()
- verify(keyguardPasswordView).hideKeyboard()
+ @Test
+ fun testFocusWhenBouncerIsShown() {
+ Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true)
+ Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
+ keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
+ keyguardPasswordView.post {
+ verify(keyguardPasswordView).requestFocus()
+ verify(keyguardPasswordView).showKeyboard()
+ }
}
- }
- @Test
- fun startAppearAnimation() {
- keyguardPasswordViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_password), false)
- }
+ @Test
+ fun testDoNotFocusWhenBouncerIsHidden() {
+ Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false)
+ Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
+ keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
+ verify(keyguardPasswordView, never()).requestFocus()
+ }
- @Test
- fun startAppearAnimation_withExistingMessage() {
- `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
- keyguardPasswordViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
- }
+ @Test
+ fun testHideKeyboardWhenOnPause() {
+ keyguardPasswordViewController.onPause()
+ keyguardPasswordView.post {
+ verify(keyguardPasswordView).clearFocus()
+ verify(keyguardPasswordView).hideKeyboard()
+ }
+ }
- @Test
- fun testMessageIsSetWhenReset() {
- keyguardPasswordViewController.resetState()
- verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password)
- }
+ @Test
+ fun testOnViewAttached() {
+ keyguardPasswordViewController.onViewAttached()
+ verify(mKeyguardMessageAreaController)
+ .setMessage(context.resources.getString(R.string.keyguard_enter_your_password), false)
+ }
+
+ @Test
+ fun testOnViewAttached_withExistingMessage() {
+ `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
+ keyguardPasswordViewController.onViewAttached()
+ verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
+ }
+
+ @Test
+ fun testMessageIsSetWhenReset() {
+ keyguardPasswordViewController.resetState()
+ verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 9f7ab7b..1acd676 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -46,6 +46,7 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -54,35 +55,35 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardPatternViewControllerTest : SysuiTestCase() {
- private lateinit var mKeyguardPatternView: KeyguardPatternView
+ private lateinit var mKeyguardPatternView: KeyguardPatternView
- @Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
+ @Mock private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
- @Mock private lateinit var mLockPatternUtils: LockPatternUtils
+ @Mock private lateinit var mLockPatternUtils: LockPatternUtils
- @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+ @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
- @Mock private lateinit var mLatencyTracker: LatencyTracker
- private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
+ @Mock private lateinit var mLatencyTracker: LatencyTracker
+ private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
- @Mock private lateinit var mEmergencyButtonController: EmergencyButtonController
+ @Mock private lateinit var mEmergencyButtonController: EmergencyButtonController
- @Mock
- private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock
+ private lateinit var mKeyguardMessageAreaControllerFactory:
+ KeyguardMessageAreaController.Factory
- @Mock
- private lateinit var mKeyguardMessageAreaController:
- KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+ @Mock
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
- @Mock private lateinit var mPostureController: DevicePostureController
+ @Mock private lateinit var mPostureController: DevicePostureController
- private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
- private lateinit var fakeFeatureFlags: FakeFeatureFlags
+ private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
+ private lateinit var fakeFeatureFlags: FakeFeatureFlags
- @Captor
- lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
+ @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
@Before
fun setup() {
@@ -91,9 +92,8 @@
.thenReturn(mKeyguardMessageAreaController)
fakeFeatureFlags = FakeFeatureFlags()
fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, false)
- mKeyguardPatternView = View.inflate(mContext, R.layout.keyguard_pattern_view, null)
- as KeyguardPatternView
-
+ mKeyguardPatternView =
+ View.inflate(mContext, R.layout.keyguard_pattern_view, null) as KeyguardPatternView
mKeyguardPatternViewController =
KeyguardPatternViewController(
@@ -125,8 +125,7 @@
@Test
fun onDevicePostureChanged_deviceOpened_propagatedToPatternView() {
overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
- whenever(mPostureController.devicePosture)
- .thenReturn(DEVICE_POSTURE_HALF_OPENED)
+ whenever(mPostureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
mKeyguardPatternViewController.onViewAttached()
@@ -159,39 +158,37 @@
return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio)
}
- @Test
- fun withFeatureFlagOn_oldMessage_isHidden() {
- fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
+ @Test
+ fun withFeatureFlagOn_oldMessage_isHidden() {
+ fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
- mKeyguardPatternViewController.onViewAttached()
+ mKeyguardPatternViewController.onViewAttached()
- verify<KeyguardMessageAreaController<*>>(mKeyguardMessageAreaController).disable()
- }
+ verify<KeyguardMessageAreaController<*>>(mKeyguardMessageAreaController).disable()
+ }
- @Test
- fun onPause_resetsText() {
- mKeyguardPatternViewController.init()
- mKeyguardPatternViewController.onPause()
- verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
- }
+ @Test
+ fun onPause_resetsText() {
+ mKeyguardPatternViewController.init()
+ mKeyguardPatternViewController.onPause()
+ verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
+ }
- @Test
- fun startAppearAnimation() {
- mKeyguardPatternViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_pattern), false)
- }
+ @Test
+ fun testOnViewAttached() {
+ reset(mKeyguardMessageAreaController)
+ reset(mLockPatternUtils)
+ mKeyguardPatternViewController.onViewAttached()
+ verify(mKeyguardMessageAreaController)
+ .setMessage(context.resources.getString(R.string.keyguard_enter_your_pattern), false)
+ verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt())
+ }
- @Test
- fun startAppearAnimation_withExistingMessage() {
- `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
- mKeyguardPatternViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
- }
-
- @Test
- fun resume() {
- mKeyguardPatternViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
- verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt())
- }
+ @Test
+ fun testOnViewAttached_withExistingMessage() {
+ reset(mKeyguardMessageAreaController)
+ `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
+ mKeyguardPatternViewController.onViewAttached()
+ verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index cf86c21..efe1955 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -100,6 +100,8 @@
.thenReturn(mDeleteButton);
when(mPinBasedInputView.findViewById(R.id.key_enter))
.thenReturn(mOkButton);
+
+ when(mPinBasedInputView.getResources()).thenReturn(getContext().getResources());
FakeFeatureFlags featureFlags = new FakeFeatureFlags();
featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 309d9e0..80fd721 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -185,27 +185,27 @@
}
@Test
- fun startAppearAnimation() {
+ fun testOnViewAttached() {
val pinViewController = constructPinViewController(mockKeyguardPinView)
- pinViewController.startAppearAnimation()
+ pinViewController.onViewAttached()
verify(keyguardMessageAreaController)
.setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
}
@Test
- fun startAppearAnimation_withExistingMessage() {
+ fun testOnViewAttached_withExistingMessage() {
val pinViewController = constructPinViewController(mockKeyguardPinView)
Mockito.`when`(keyguardMessageAreaController.message).thenReturn("Unlock to continue.")
- pinViewController.startAppearAnimation()
+ pinViewController.onViewAttached()
verify(keyguardMessageAreaController, Mockito.never()).setMessage(anyString(), anyBoolean())
}
@Test
- fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() {
+ fun testOnViewAttached_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() {
val pinViewController = constructPinViewController(mockKeyguardPinView)
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
@@ -213,7 +213,7 @@
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3)
`when`(passwordTextView.text).thenReturn("")
- pinViewController.startAppearAnimation()
+ pinViewController.onViewAttached()
verify(deleteButton).visibility = View.INVISIBLE
verify(enterButton).visibility = View.INVISIBLE
@@ -222,7 +222,7 @@
}
@Test
- fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() {
+ fun testOnViewAttached_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() {
val pinViewController = constructPinViewController(mockKeyguardPinView)
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
@@ -230,7 +230,7 @@
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6)
`when`(passwordTextView.text).thenReturn("")
- pinViewController.startAppearAnimation()
+ pinViewController.onViewAttached()
verify(deleteButton).visibility = View.VISIBLE
verify(enterButton).visibility = View.VISIBLE
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 17bb3d5..b5317fa 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -58,12 +58,15 @@
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argThat
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.GlobalSettings
@@ -133,6 +136,7 @@
@Mock private lateinit var audioManager: AudioManager
@Mock private lateinit var userInteractor: UserInteractor
@Mock private lateinit var faceAuthAccessibilityDelegate: FaceAuthAccessibilityDelegate
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Captor
private lateinit var swipeListenerArgumentCaptor:
@@ -182,6 +186,7 @@
whenever(keyguardPasswordView.windowInsetsController).thenReturn(windowInsetsController)
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN)
whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true)
+ whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(true)
featureFlags = FakeFeatureFlags()
featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
@@ -249,6 +254,7 @@
mock(),
{ JavaAdapter(sceneTestUtils.testScope.backgroundScope) },
userInteractor,
+ deviceProvisionedController,
faceAuthAccessibilityDelegate,
keyguardTransitionInteractor,
{ authenticationInteractor },
@@ -505,6 +511,30 @@
// THEN the next security method of None will dismiss keyguard.
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
}
+ @Test
+ fun showNextSecurityScreenOrFinish_SimPin_Swipe_userNotSetup() {
+ // GIVEN the current security method is SimPin
+ whenever(keyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false)
+ whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID))
+ .thenReturn(false)
+ underTest.showSecurityScreen(SecurityMode.SimPin)
+
+ // WHEN a request is made from the SimPin screens to show the next security method
+ whenever(keyguardSecurityModel.getSecurityMode(TARGET_USER_ID))
+ .thenReturn(SecurityMode.None)
+ // WHEN security method is SWIPE
+ whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
+ whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(false)
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN the next security method of None will dismiss keyguard.
+ verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
+ }
@Test
fun onSwipeUp_whenFaceDetectionIsNotRunning_initiatesFaceAuth() {
@@ -577,18 +607,7 @@
ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
underTest.onViewAttached()
verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
- clearInvocations(viewFlipperController)
configurationListenerArgumentCaptor.value.onThemeChanged()
- verify(viewFlipperController).clearViews()
- verify(viewFlipperController)
- .asynchronouslyInflateView(
- eq(SecurityMode.PIN),
- any(),
- onViewInflatedCallbackArgumentCaptor.capture()
- )
- onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
- verify(view).reset()
- verify(viewFlipperController).reset()
verify(view).reloadColors()
}
@@ -598,8 +617,46 @@
ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
underTest.onViewAttached()
verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
- clearInvocations(viewFlipperController)
configurationListenerArgumentCaptor.value.onUiModeChanged()
+ verify(view).reloadColors()
+ }
+ @Test
+ fun onOrientationChanged_landscapeKeyguardFlagDisabled_blockReinflate() {
+ featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
+
+ // Run onOrientationChanged
+ val configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ underTest.onViewAttached()
+ verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+ clearInvocations(viewFlipperController)
+ configurationListenerArgumentCaptor.value.onOrientationChanged(
+ Configuration.ORIENTATION_LANDSCAPE
+ )
+ // Verify view is reinflated when flag is on
+ verify(viewFlipperController, never()).clearViews()
+ verify(viewFlipperController, never())
+ .asynchronouslyInflateView(
+ eq(SecurityMode.PIN),
+ any(),
+ onViewInflatedCallbackArgumentCaptor.capture()
+ )
+ }
+
+ @Test
+ fun onOrientationChanged_landscapeKeyguardFlagEnabled_doesReinflate() {
+ featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true)
+
+ // Run onOrientationChanged
+ val configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ underTest.onViewAttached()
+ verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+ clearInvocations(viewFlipperController)
+ configurationListenerArgumentCaptor.value.onOrientationChanged(
+ Configuration.ORIENTATION_LANDSCAPE
+ )
+ // Verify view is reinflated when flag is on
verify(viewFlipperController).clearViews()
verify(viewFlipperController)
.asynchronouslyInflateView(
@@ -607,8 +664,6 @@
any(),
onViewInflatedCallbackArgumentCaptor.capture()
)
- onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
- verify(view).reloadColors()
}
@Test
@@ -876,6 +931,17 @@
verify(userSwitcher).setAlpha(0f)
}
+ @Test
+ fun testOnUserSwitched() {
+ val userSwitchCallbackArgumentCaptor =
+ argumentCaptor<UserSwitcherController.UserSwitchCallback>()
+ underTest.onViewAttached()
+ verify(userSwitcherController)
+ .addUserSwitchCallback(capture(userSwitchCallbackArgumentCaptor))
+ userSwitchCallbackArgumentCaptor.value.onUserSwitched()
+ verify(viewFlipperController).asynchronouslyInflateView(any(), any(), any())
+ }
+
private val registeredSwipeListener: KeyguardSecurityContainer.SwipeListener
get() {
underTest.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index a3acc78..291dda25 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -97,6 +97,8 @@
@Test
fun onViewAttached() {
underTest.onViewAttached()
+ verify(keyguardMessageAreaController)
+ .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
}
@Test
@@ -120,8 +122,6 @@
@Test
fun startAppearAnimation() {
underTest.startAppearAnimation()
- verify(keyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index efcf4dd..626faa6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -98,6 +98,8 @@
underTest.onViewAttached()
Mockito.verify(keyguardUpdateMonitor)
.registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
+ Mockito.verify(keyguardMessageAreaController)
+ .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
}
@Test
@@ -120,8 +122,6 @@
@Test
fun startAppearAnimation() {
underTest.startAppearAnimation()
- Mockito.verify(keyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 7d23c80..b8b0198 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -77,7 +77,7 @@
public void updatePosition_primaryClockAnimation() {
ClockController mockClock = mock(ClockController.class);
when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
- when(mockClock.getConfig()).thenReturn(new ClockConfig(false, true));
+ when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true));
mController.updatePosition(10, 15, 20f, true);
@@ -92,7 +92,7 @@
public void updatePosition_alternateClockAnimation() {
ClockController mockClock = mock(ClockController.class);
when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
- when(mockClock.getConfig()).thenReturn(new ClockConfig(true, true));
+ when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true));
mController.updatePosition(10, 15, 20f, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
index efae3fe..8eb274a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
@@ -24,13 +24,12 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.StringSubject
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -39,13 +38,12 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class BouncerMessageFactoryTest : SysuiTestCase() {
private lateinit var underTest: BouncerMessageFactory
- @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Mock private lateinit var securityModel: KeyguardSecurityModel
@@ -55,7 +53,8 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
- underTest = BouncerMessageFactory(updateMonitor, securityModel)
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
+ underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel)
}
@Test
@@ -167,7 +166,7 @@
secondaryMessageOverride: String? = null,
): BouncerMessageModel? {
whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
- whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed)
return underTest.createFromPromptReason(
reason,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
index 2be7d8a..562a8ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
@@ -101,14 +101,15 @@
fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
testScope = TestScope()
- whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
underTest =
BouncerMessageRepositoryImpl(
trustRepository = trustRepository,
biometricSettingsRepository = biometricSettingsRepository,
updateMonitor = updateMonitor,
- bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel),
+ bouncerMessageFactory =
+ BouncerMessageFactory(biometricSettingsRepository, securityModel),
userRepository = userRepository,
fingerprintAuthRepository = fingerprintRepository,
systemPropertiesHelper = systemPropertiesHelper
@@ -222,8 +223,7 @@
whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
.thenReturn("reboot,mainline_update")
userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setFaceEnrolled(true)
- biometricSettingsRepository.setIsFaceAuthEnabled(true)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
verifyMessagesForAuthFlag(
STRONG_AUTH_REQUIRED_AFTER_BOOT to
@@ -236,8 +236,8 @@
testScope.runTest {
userRepository.setSelectedUserInfo(PRIMARY_USER)
trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setFaceEnrolled(false)
- biometricSettingsRepository.setFingerprintEnrolled(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
verifyMessagesForAuthFlag(
STRONG_AUTH_NOT_REQUIRED to null,
@@ -258,8 +258,8 @@
fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
testScope.runTest {
userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setFaceEnrolled(false)
- biometricSettingsRepository.setFingerprintEnrolled(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
trustRepository.setCurrentUserTrustManaged(true)
@@ -290,10 +290,9 @@
testScope.runTest {
userRepository.setSelectedUserInfo(PRIMARY_USER)
trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setFingerprintEnrolled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setIsFaceAuthEnabled(true)
- biometricSettingsRepository.setFaceEnrolled(true)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
verifyMessagesForAuthFlag(
STRONG_AUTH_NOT_REQUIRED to null,
@@ -320,11 +319,9 @@
testScope.runTest {
userRepository.setSelectedUserInfo(PRIMARY_USER)
trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFaceAuthEnabled(false)
- biometricSettingsRepository.setFaceEnrolled(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setFingerprintEnrolled(true)
- biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
verifyMessagesForAuthFlag(
STRONG_AUTH_NOT_REQUIRED to null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 38e5728..0d17270 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -94,9 +94,9 @@
}
@Test
- fun canShowAlternateBouncerForFingerprint_noFingerprintsEnrolled() {
+ fun canShowAlternateBouncerForFingerprint_ifFingerprintIsNotUsuallyAllowed() {
givenCanShowAlternateBouncer()
- biometricSettingsRepository.setFingerprintEnrolled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
}
@@ -104,15 +104,7 @@
@Test
fun canShowAlternateBouncerForFingerprint_strongBiometricNotAllowed() {
givenCanShowAlternateBouncer()
- biometricSettingsRepository.setStrongBiometricAllowed(false)
-
- assertFalse(underTest.canShowAlternateBouncerForFingerprint())
- }
-
- @Test
- fun canShowAlternateBouncerForFingerprint_devicePolicyDoesNotAllowFingerprint() {
- givenCanShowAlternateBouncer()
- biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(false)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
}
@@ -189,14 +181,13 @@
private fun givenCanShowAlternateBouncer() {
bouncerRepository.setAlternateBouncerUIAvailable(true)
- biometricSettingsRepository.setFingerprintEnrolled(true)
- biometricSettingsRepository.setStrongBiometricAllowed(true)
- biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
whenever(keyguardStateController.isUnlocked).thenReturn(false)
}
private fun givenCannotShowAlternateBouncer() {
- biometricSettingsRepository.setFingerprintEnrolled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index 3ca94aa..4089abe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -22,9 +22,8 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.R.string.keyguard_enter_pin
import com.android.systemui.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.R.string.kg_unlock_with_pin_or_fp
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
@@ -34,11 +33,11 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -49,14 +48,13 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4::class)
class BouncerMessageInteractorTest : SysuiTestCase() {
@Mock private lateinit var securityModel: KeyguardSecurityModel
- @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Mock private lateinit var countDownTimerUtil: CountDownTimerUtil
private lateinit var countDownTimerCallback: KotlinArgumentCaptor<CountDownTimerCallback>
private lateinit var underTest: BouncerMessageInteractor
@@ -73,10 +71,11 @@
userRepository.setUserInfos(listOf(PRIMARY_USER))
testScope = TestScope()
countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
- whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
}
suspend fun TestScope.init() {
@@ -86,7 +85,7 @@
underTest =
BouncerMessageInteractor(
repository = repository,
- factory = BouncerMessageFactory(updateMonitor, securityModel),
+ factory = BouncerMessageFactory(biometricSettingsRepository, securityModel),
userRepository = userRepository,
countDownTimerUtil = countDownTimerUtil,
featureFlags = featureFlags
@@ -151,7 +150,8 @@
underTest.setCustomMessage("not empty")
val customMessage = repository.customMessage
- assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
+ assertThat(customMessage.value!!.message!!.messageResId)
+ .isEqualTo(kg_unlock_with_pin_or_fp)
assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
underTest.setCustomMessage(null)
@@ -168,7 +168,7 @@
val faceAcquisitionMessage = repository.faceAcquisitionMessage
assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(keyguard_enter_pin)
+ .isEqualTo(kg_unlock_with_pin_or_fp)
assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
.isEqualTo("not empty")
@@ -186,7 +186,7 @@
val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(keyguard_enter_pin)
+ .isEqualTo(kg_unlock_with_pin_or_fp)
assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
.isEqualTo("not empty")
@@ -275,7 +275,8 @@
repository.setBiometricLockedOutMessage(null)
// sets the default message if everything else is null
- assertThat(bouncerMessage()!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
+ assertThat(bouncerMessage()!!.message!!.messageResId)
+ .isEqualTo(kg_unlock_with_pin_or_fp)
}
private fun message(value: String): BouncerMessageModel {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
index 7628be4..662c89c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
@@ -80,6 +80,7 @@
assertEquals(Intent.ACTION_EDIT, intent.getAction());
assertEquals("image/*", intent.getType());
assertEquals(null, intent.getComponent());
+ assertEquals("clipboard", intent.getStringExtra("edit_source"));
assertFlags(intent, EXTERNAL_INTENT_FLAGS);
// try again with an editor component
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index 692d794..8416c46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -18,12 +18,14 @@
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
+import android.view.HapticFeedbackConstants
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -33,6 +35,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyBoolean
@@ -68,8 +71,6 @@
@Mock
private lateinit var metricsLogger: ControlsMetricsLogger
@Mock
- private lateinit var featureFlags: FeatureFlags
- @Mock
private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager
companion object {
@@ -82,6 +83,8 @@
private lateinit var action: ControlActionCoordinatorImpl.Action
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
+ private val featureFlags = FakeFeatureFlags()
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -101,6 +104,7 @@
metricsLogger,
vibratorHelper,
controlsSettingsRepository,
+ featureFlags
))
coordinator.activityContext = mContext
@@ -194,4 +198,50 @@
verify(coordinator).bouncerOrRun(action)
verify(action, never()).invoke()
}
+
+ @Test
+ fun drag_isEdge_oneWayHapticsDisabled_usesVibrate() {
+ featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false)
+
+ coordinator.drag(cvh, true)
+
+ verify(vibratorHelper).vibrate(
+ Vibrations.rangeEdgeEffect
+ )
+ }
+
+ @Test
+ fun drag_isNotEdge_oneWayHapticsDisabled_usesVibrate() {
+ featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false)
+
+ coordinator.drag(cvh, false)
+
+ verify(vibratorHelper).vibrate(
+ Vibrations.rangeMiddleEffect
+ )
+ }
+
+ @Test
+ fun drag_isEdge_oneWayHapticsEnabled_usesPerformHapticFeedback() {
+ featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true)
+
+ coordinator.drag(cvh, true)
+
+ verify(vibratorHelper).performHapticFeedback(
+ any(),
+ eq(HapticFeedbackConstants.SEGMENT_TICK)
+ )
+ }
+
+ @Test
+ fun drag_isNotEdge_oneWayHapticsEnabled_usesPerformHapticFeedback() {
+ featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true)
+
+ coordinator.drag(cvh, false)
+
+ verify(vibratorHelper).performHapticFeedback(
+ any(),
+ eq(HapticFeedbackConstants.SEGMENT_FREQUENT_TICK)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index 07cb5d8..6a17889 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -22,17 +22,14 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.IVisualQueryDetectionAttentionListener;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
import com.android.systemui.shared.condition.Condition;
import org.junit.Before;
@@ -50,9 +47,7 @@
@Mock
Condition.Callback mCallback;
@Mock
- AssistUtils mAssistUtils;
- @Mock
- DreamOverlayStateController mDreamOverlayStateController;
+ AssistManager mAssistManager;
@Mock
CoroutineScope mScope;
@@ -62,55 +57,34 @@
public void setup() {
MockitoAnnotations.initMocks(this);
- mAssistantAttentionCondition =
- new AssistantAttentionCondition(mScope, mDreamOverlayStateController, mAssistUtils);
+ mAssistantAttentionCondition = new AssistantAttentionCondition(mScope, mAssistManager);
// Adding a callback also starts the condition.
mAssistantAttentionCondition.addCallback(mCallback);
}
@Test
public void testEnableVisualQueryDetection() {
- final ArgumentCaptor<DreamOverlayStateController.Callback> argumentCaptor =
- ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
- verify(mDreamOverlayStateController).addCallback(argumentCaptor.capture());
-
- when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
- argumentCaptor.getValue().onStateChanged();
-
- verify(mAssistUtils).enableVisualQueryDetection(any());
+ verify(mAssistManager).addVisualQueryAttentionListener(
+ any(VisualQueryAttentionListener.class));
}
@Test
public void testDisableVisualQueryDetection() {
- final ArgumentCaptor<DreamOverlayStateController.Callback> argumentCaptor =
- ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
- verify(mDreamOverlayStateController).addCallback(argumentCaptor.capture());
-
- when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
- argumentCaptor.getValue().onStateChanged();
- when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(false);
- argumentCaptor.getValue().onStateChanged();
-
- verify(mAssistUtils).disableVisualQueryDetection();
+ mAssistantAttentionCondition.stop();
+ verify(mAssistManager).removeVisualQueryAttentionListener(
+ any(VisualQueryAttentionListener.class));
}
@Test
- public void testAttentionChangedTriggersCondition() throws RemoteException {
- final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
- ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
- verify(mDreamOverlayStateController).addCallback(callbackCaptor.capture());
+ public void testAttentionChangedTriggersCondition() {
+ final ArgumentCaptor<VisualQueryAttentionListener> argumentCaptor =
+ ArgumentCaptor.forClass(VisualQueryAttentionListener.class);
+ verify(mAssistManager).addVisualQueryAttentionListener(argumentCaptor.capture());
- when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
- callbackCaptor.getValue().onStateChanged();
-
- final ArgumentCaptor<IVisualQueryDetectionAttentionListener> listenerCaptor =
- ArgumentCaptor.forClass(IVisualQueryDetectionAttentionListener.class);
- verify(mAssistUtils).enableVisualQueryDetection(listenerCaptor.capture());
-
- listenerCaptor.getValue().onAttentionGained();
+ argumentCaptor.getValue().onAttentionGained();
assertThat(mAssistantAttentionCondition.isConditionMet()).isTrue();
- listenerCaptor.getValue().onAttentionLost();
+ argumentCaptor.getValue().onAttentionLost();
assertThat(mAssistantAttentionCondition.isConditionMet()).isFalse();
verify(mCallback, times(2)).onConditionChanged(eq(mAssistantAttentionCondition));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
new file mode 100644
index 0000000..632d149
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.keyevent.domain.interactor
+
+import android.view.KeyEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyEventInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ private lateinit var keyguardInteractorWithDependencies:
+ KeyguardInteractorFactory.WithDependencies
+ @Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor
+ @Mock private lateinit var backActionInteractor: BackActionInteractor
+
+ private lateinit var underTest: KeyEventInteractor
+
+ @Before
+ fun setup() {
+ keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
+ underTest =
+ KeyEventInteractor(
+ backActionInteractor,
+ keyguardKeyEventInteractor,
+ )
+ }
+
+ @Test
+ fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() {
+ val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)
+ val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
+
+ // GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor
+ whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown))
+ .thenReturn(false)
+ whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp))
+ .thenReturn(false)
+
+ // WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested
+ assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue()
+ // THEN back event isn't handled on ACTION_DOWN
+ verify(backActionInteractor, never()).onBackRequested()
+
+ // WHEN back key event ACTION_UP
+ assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue()
+ // THEN back event is handled on ACTION_UP
+ verify(backActionInteractor).onBackRequested()
+ }
+
+ @Test
+ fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false)
+ assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse()
+ }
+
+ @Test
+ fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true)
+ assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue()
+ }
+
+ @Test
+ fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false)
+ assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
+ }
+
+ @Test
+ fun interceptMediaKey_handledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true)
+ assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
+ }
+
+ @Test
+ fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false)
+ assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse()
+ }
+
+ @Test
+ fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() {
+ val keyEvent =
+ KeyEvent(
+ KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SPACE,
+ )
+ whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true)
+ assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index c6a2fa5..a6930d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -36,6 +36,11 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.BiometricType.FACE
@@ -63,6 +68,7 @@
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -89,6 +95,8 @@
ArgumentCaptor<IBiometricEnabledOnKeyguardCallback.Stub>
private lateinit var userRepository: FakeUserRepository
private lateinit var devicePostureRepository: FakeDevicePostureRepository
+ private lateinit var facePropertyRepository: FakeFacePropertyRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
@@ -102,6 +110,8 @@
testScope = TestScope(testDispatcher)
userRepository = FakeUserRepository()
devicePostureRepository = FakeDevicePostureRepository()
+ facePropertyRepository = FakeFacePropertyRepository()
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
}
private suspend fun createBiometricSettingsRepository() {
@@ -120,74 +130,110 @@
biometricManager = biometricManager,
devicePostureRepository = devicePostureRepository,
dumpManager = dumpManager,
+ facePropertyRepository = facePropertyRepository,
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
)
testScope.runCurrent()
+ fingerprintPropertyRepository.setProperties(
+ 1,
+ SensorStrength.STRONG,
+ FingerprintSensorType.UDFPS_OPTICAL,
+ emptyMap()
+ )
verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture())
+ verify(authController, atLeastOnce()).addCallback(authControllerCallback.capture())
}
@Test
fun fingerprintEnrollmentChange() =
testScope.runTest {
createBiometricSettingsRepository()
- val fingerprintEnrolled = collectLastValue(underTest.isFingerprintEnrolled)
+ val fingerprintAllowed = collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
runCurrent()
- verify(authController).addCallback(authControllerCallback.capture())
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true)
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
- assertThat(fingerprintEnrolled()).isTrue()
+ assertThat(fingerprintAllowed()).isTrue()
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false)
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, ANOTHER_USER_ID, false)
- assertThat(fingerprintEnrolled()).isTrue()
+ assertThat(fingerprintAllowed()).isTrue()
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, false)
- assertThat(fingerprintEnrolled()).isFalse()
+ assertThat(fingerprintAllowed()).isFalse()
}
@Test
fun strongBiometricAllowedChange() =
testScope.runTest {
+ fingerprintIsEnrolled()
+ doNotDisableKeyguardAuthFeatures()
createBiometricSettingsRepository()
- val strongBiometricAllowed = collectLastValue(underTest.isStrongBiometricAllowed)
+
+ val strongBiometricAllowed by
+ collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
runCurrent()
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
- assertThat(strongBiometricAllowed()).isTrue()
+ assertThat(strongBiometricAllowed).isTrue()
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID)
- assertThat(strongBiometricAllowed()).isFalse()
+ assertThat(strongBiometricAllowed).isFalse()
}
@Test
fun convenienceBiometricAllowedChange() =
testScope.runTest {
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false)
+ deviceIsInPostureThatSupportsFaceAuth()
+ faceAuthIsEnrolled()
+ faceAuthIsNonStrongBiometric()
createBiometricSettingsRepository()
- val convenienceBiometricAllowed =
- collectLastValue(underTest.isNonStrongBiometricAllowed)
- runCurrent()
+ val convenienceFaceAuthAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
+ doNotDisableKeyguardAuthFeatures()
+ faceAuthIsEnabledByBiometricManager()
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
- assertThat(convenienceBiometricAllowed()).isTrue()
+ runCurrent()
+ assertThat(convenienceFaceAuthAllowed).isTrue()
onNonStrongAuthChanged(false, ANOTHER_USER_ID)
- assertThat(convenienceBiometricAllowed()).isTrue()
+ assertThat(convenienceFaceAuthAllowed).isTrue()
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
- assertThat(convenienceBiometricAllowed()).isFalse()
+ assertThat(convenienceFaceAuthAllowed).isFalse()
mContext.orCreateTestableResources.removeOverride(
com.android.internal.R.bool.config_strongAuthRequiredOnBoot
)
}
+ private fun faceAuthIsNonStrongBiometric() {
+ facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE))
+ }
+
+ private fun faceAuthIsStrongBiometric() {
+ facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
+ }
+
+ private fun deviceIsInPostureThatSupportsFaceAuth() {
+ overrideResource(
+ R.integer.config_face_auth_supported_posture,
+ DevicePostureController.DEVICE_POSTURE_FLIPPED
+ )
+ devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED)
+ }
+
@Test
fun whenStrongAuthRequiredAfterBoot_nonStrongBiometricNotAllowed() =
testScope.runTest {
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, true)
createBiometricSettingsRepository()
+ faceAuthIsNonStrongBiometric()
+ faceAuthIsEnrolled()
+ doNotDisableKeyguardAuthFeatures()
- val convenienceBiometricAllowed =
- collectLastValue(underTest.isNonStrongBiometricAllowed)
+ val convenienceBiometricAllowed = collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
runCurrent()
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
@@ -201,16 +247,24 @@
fun whenStrongBiometricAuthIsNotAllowed_nonStrongBiometrics_alsoNotAllowed() =
testScope.runTest {
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false)
+ faceAuthIsNonStrongBiometric()
+ deviceIsInPostureThatSupportsFaceAuth()
+ faceAuthIsEnrolled()
createBiometricSettingsRepository()
-
- val convenienceBiometricAllowed =
- collectLastValue(underTest.isNonStrongBiometricAllowed)
+ doNotDisableKeyguardAuthFeatures()
+ faceAuthIsEnabledByBiometricManager()
runCurrent()
+
+ val convenienceBiometricAllowed by
+ collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
- assertThat(convenienceBiometricAllowed()).isTrue()
+ runCurrent()
+ assertThat(convenienceBiometricAllowed).isTrue()
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, PRIMARY_USER_ID)
- assertThat(convenienceBiometricAllowed()).isFalse()
+ assertThat(convenienceBiometricAllowed).isFalse()
mContext.orCreateTestableResources.removeOverride(
com.android.internal.R.bool.config_strongAuthRequiredOnBoot
)
@@ -229,9 +283,11 @@
@Test
fun fingerprintDisabledByDpmChange() =
testScope.runTest {
+ fingerprintIsEnrolled(PRIMARY_USER_ID)
createBiometricSettingsRepository()
+
val fingerprintEnabledByDevicePolicy =
- collectLastValue(underTest.isFingerprintEnabledByDevicePolicy)
+ collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
runCurrent()
whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
@@ -244,43 +300,57 @@
assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
}
+ private fun fingerprintIsEnrolled(userId: Int = PRIMARY_USER_ID) {
+ whenever(authController.isFingerprintEnrolled(userId)).thenReturn(true)
+ }
+
@Test
fun faceEnrollmentChangeIsPropagatedForTheCurrentUser() =
testScope.runTest {
createBiometricSettingsRepository()
+ faceAuthIsEnabledByBiometricManager()
+
+ doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
+
runCurrent()
clearInvocations(authController)
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
- val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
+ val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
verify(authController).addCallback(authControllerCallback.capture())
enrollmentChange(REAR_FINGERPRINT, PRIMARY_USER_ID, true)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
enrollmentChange(SIDE_FINGERPRINT, PRIMARY_USER_ID, true)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
enrollmentChange(FACE, ANOTHER_USER_ID, true)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
- whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(true)
+ faceAuthIsEnrolled()
enrollmentChange(FACE, PRIMARY_USER_ID, true)
- assertThat(faceEnrolled()).isTrue()
+ assertThat(faceAuthAllowed()).isTrue()
}
+ private fun faceAuthIsEnabledByBiometricManager(userId: Int = PRIMARY_USER_ID) {
+ verify(biometricManager, atLeastOnce())
+ .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
+ biometricManagerCallback.value.onChanged(true, userId)
+ }
+
@Test
fun faceEnrollmentStatusOfNewUserUponUserSwitch() =
testScope.runTest {
@@ -290,21 +360,26 @@
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
- val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
+ val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
- assertThat(faceEnrolled()).isFalse()
+ assertThat(faceAuthAllowed()).isFalse()
}
@Test
fun faceEnrollmentChangesArePropagatedAfterUserSwitch() =
testScope.runTest {
createBiometricSettingsRepository()
+ verify(biometricManager)
+ .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
userRepository.setSelectedUserInfo(ANOTHER_USER)
+ doNotDisableKeyguardAuthFeatures(ANOTHER_USER_ID)
+ biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
+
runCurrent()
clearInvocations(authController)
- val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
+ val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
runCurrent()
verify(authController).addCallback(authControllerCallback.capture())
@@ -312,12 +387,14 @@
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
enrollmentChange(FACE, ANOTHER_USER_ID, true)
- assertThat(faceEnrolled()).isTrue()
+ assertThat(faceAuthAllowed()).isTrue()
}
@Test
fun devicePolicyControlsFaceAuthenticationEnabledState() =
testScope.runTest {
+ faceAuthIsEnrolled()
+
createBiometricSettingsRepository()
verify(biometricManager)
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
@@ -325,62 +402,70 @@
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT or KEYGUARD_DISABLE_FACE)
- val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
+ val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
runCurrent()
broadcastDPMStateChange()
- assertThat(isFaceAuthEnabled()).isFalse()
+ assertThat(isFaceAuthAllowed()).isFalse()
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
runCurrent()
- assertThat(isFaceAuthEnabled()).isFalse()
+ assertThat(isFaceAuthAllowed()).isFalse()
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT)
broadcastDPMStateChange()
- assertThat(isFaceAuthEnabled()).isTrue()
+ assertThat(isFaceAuthAllowed()).isTrue()
}
@Test
fun biometricManagerControlsFaceAuthenticationEnabledStatus() =
testScope.runTest {
+ faceAuthIsEnrolled()
+
createBiometricSettingsRepository()
verify(biometricManager)
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(0)
broadcastDPMStateChange()
- val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
+ val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
- assertThat(isFaceAuthEnabled()).isFalse()
+ assertThat(isFaceAuthAllowed()).isFalse()
// Value changes for another user
biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
- assertThat(isFaceAuthEnabled()).isFalse()
+ assertThat(isFaceAuthAllowed()).isFalse()
// Value changes for current user.
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
- assertThat(isFaceAuthEnabled()).isTrue()
+ assertThat(isFaceAuthAllowed()).isTrue()
}
+ private fun faceAuthIsEnrolled(userId: Int = PRIMARY_USER_ID) {
+ whenever(authController.isFaceAuthEnrolled(userId)).thenReturn(true)
+ }
+
@Test
fun userChange_biometricEnabledChange_handlesRaceCondition() =
testScope.runTest {
createBiometricSettingsRepository()
+ whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
+
verify(biometricManager)
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
- val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
+ val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
runCurrent()
userRepository.setSelectedUserInfo(ANOTHER_USER)
runCurrent()
- assertThat(isFaceAuthEnabled()).isTrue()
+ assertThat(isFaceAuthAllowed()).isTrue()
}
@Test
@@ -388,9 +473,9 @@
testScope.runTest {
createBiometricSettingsRepository()
- collectLastValue(underTest.isFaceAuthenticationEnabled)()
- collectLastValue(underTest.isFaceAuthenticationEnabled)()
- collectLastValue(underTest.isFaceAuthenticationEnabled)()
+ collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
+ collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
+ collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
verify(biometricManager, times(1)).registerEnabledOnKeyguardCallback(any())
}
@@ -495,10 +580,138 @@
assertThat(authFlags()!!.flag).isEqualTo(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT)
}
+ @Test
+ fun faceAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFaceIsClass3() =
+ testScope.runTest {
+ createBiometricSettingsRepository()
+ val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
+
+ faceAuthIsEnrolled()
+ deviceIsInPostureThatSupportsFaceAuth()
+ doNotDisableKeyguardAuthFeatures()
+ faceAuthIsStrongBiometric()
+ faceAuthIsEnabledByBiometricManager()
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(false, PRIMARY_USER_ID)
+
+ assertThat(isFaceAuthCurrentlyAllowed).isTrue()
+
+ onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(true, PRIMARY_USER_ID)
+
+ assertThat(isFaceAuthCurrentlyAllowed).isFalse()
+ }
+
+ @Test
+ fun faceAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFaceIsNotStrong() =
+ testScope.runTest {
+ createBiometricSettingsRepository()
+ val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
+
+ faceAuthIsEnrolled()
+ deviceIsInPostureThatSupportsFaceAuth()
+ doNotDisableKeyguardAuthFeatures()
+ faceAuthIsNonStrongBiometric()
+ faceAuthIsEnabledByBiometricManager()
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(false, PRIMARY_USER_ID)
+
+ assertThat(isFaceAuthCurrentlyAllowed).isFalse()
+
+ onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(true, PRIMARY_USER_ID)
+
+ assertThat(isFaceAuthCurrentlyAllowed).isFalse()
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(true, PRIMARY_USER_ID)
+
+ assertThat(isFaceAuthCurrentlyAllowed).isTrue()
+ }
+
+ @Test
+ fun fpAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFpIsNotStrong() =
+ testScope.runTest {
+ createBiometricSettingsRepository()
+ val isFingerprintCurrentlyAllowed by
+ collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ fingerprintIsEnrolled(PRIMARY_USER_ID)
+ enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
+ doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
+ runCurrent()
+
+ fingerprintPropertyRepository.setProperties(
+ 1,
+ SensorStrength.STRONG,
+ FingerprintSensorType.UDFPS_OPTICAL,
+ emptyMap()
+ )
+ // Non strong auth is not allowed now, FP is marked strong
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(false, PRIMARY_USER_ID)
+
+ assertThat(isFingerprintCurrentlyAllowed).isTrue()
+
+ fingerprintPropertyRepository.setProperties(
+ 1,
+ SensorStrength.CONVENIENCE,
+ FingerprintSensorType.UDFPS_OPTICAL,
+ emptyMap()
+ )
+ assertThat(isFingerprintCurrentlyAllowed).isFalse()
+
+ fingerprintPropertyRepository.setProperties(
+ 1,
+ SensorStrength.WEAK,
+ FingerprintSensorType.UDFPS_OPTICAL,
+ emptyMap()
+ )
+ assertThat(isFingerprintCurrentlyAllowed).isFalse()
+ }
+
+ @Test
+ fun fpAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFpIsStrong() =
+ testScope.runTest {
+ createBiometricSettingsRepository()
+ val isFingerprintCurrentlyAllowed by
+ collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ fingerprintIsEnrolled(PRIMARY_USER_ID)
+ enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
+ doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
+ runCurrent()
+
+ fingerprintPropertyRepository.setProperties(
+ 1,
+ SensorStrength.STRONG,
+ FingerprintSensorType.UDFPS_OPTICAL,
+ emptyMap()
+ )
+ // Non strong auth is not allowed now, FP is marked strong
+ onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(true, PRIMARY_USER_ID)
+
+ assertThat(isFingerprintCurrentlyAllowed).isFalse()
+
+ onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ onNonStrongAuthChanged(false, PRIMARY_USER_ID)
+
+ assertThat(isFingerprintCurrentlyAllowed).isTrue()
+ }
+
private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) {
authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled)
}
+ private fun doNotDisableKeyguardAuthFeatures(userId: Int = PRIMARY_USER_ID) {
+ whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(userId)))
+ .thenReturn(0)
+ broadcastDPMStateChange()
+ }
+
private fun broadcastDPMStateChange() {
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index fe5b812..64b9470 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -40,9 +40,7 @@
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.data.repository.FaceSensorInfo
import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
-import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.coroutines.FlowValue
@@ -255,7 +253,6 @@
faceAuthBuffer,
keyguardTransitionInteractor,
featureFlags,
- fakeFacePropertyRepository,
dumpManager,
)
}
@@ -525,15 +522,11 @@
}
@Test
- fun authenticateDoesNotRunIfFaceIsNotEnrolled() =
+ fun authenticateDoesNotRunIfFaceIsNotUsuallyAllowed() =
testScope.runTest {
- testGatingCheckForFaceAuth { biometricSettingsRepository.setFaceEnrolled(false) }
- }
-
- @Test
- fun authenticateDoesNotRunIfFaceIsNotEnabled() =
- testScope.runTest {
- testGatingCheckForFaceAuth { biometricSettingsRepository.setIsFaceAuthEnabled(false) }
+ testGatingCheckForFaceAuth {
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ }
}
@Test
@@ -589,21 +582,10 @@
}
@Test
- fun authenticateDoesNotRunWhenNonStrongBiometricIsNotAllowed() =
+ fun authenticateDoesNotRunWhenFaceAuthIsNotCurrentlyAllowedToRun() =
testScope.runTest {
testGatingCheckForFaceAuth {
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
- }
- }
-
- @Test
- fun authenticateDoesNotRunWhenStrongBiometricIsNotAllowedAndFaceSensorIsStrong() =
- testScope.runTest {
- fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
- runCurrent()
-
- testGatingCheckForFaceAuth(isFaceStrong = true) {
- biometricSettingsRepository.setIsStrongBiometricAllowed(false)
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
}
}
@@ -662,7 +644,7 @@
allPreconditionsToRunFaceAuthAreTrue()
// Flip one precondition to false.
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
assertThat(canFaceAuthRun()).isFalse()
underTest.authenticate(
FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
@@ -827,15 +809,11 @@
}
@Test
- fun detectDoesNotRunWhenFaceIsNotEnrolled() =
+ fun detectDoesNotRunWhenFaceIsNotUsuallyAllowed() =
testScope.runTest {
- testGatingCheckForDetect { biometricSettingsRepository.setFaceEnrolled(false) }
- }
-
- @Test
- fun detectDoesNotRunWhenFaceIsNotEnabled() =
- testScope.runTest {
- testGatingCheckForDetect { biometricSettingsRepository.setIsFaceAuthEnabled(false) }
+ testGatingCheckForDetect {
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ }
}
@Test
@@ -932,23 +910,10 @@
}
@Test
- fun detectDoesNotRunWhenNonStrongBiometricIsAllowed() =
+ fun detectDoesNotRunWhenFaceAuthIsCurrentlyAllowedToRun() =
testScope.runTest {
testGatingCheckForDetect {
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
- }
- }
-
- @Test
- fun detectDoesNotRunWhenStrongBiometricIsAllowedAndFaceAuthSensorStrengthIsStrong() =
- testScope.runTest {
- fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
- runCurrent()
-
- testGatingCheckForDetect(isFaceStrong = true) {
- biometricSettingsRepository.setIsStrongBiometricAllowed(true)
- // this shouldn't matter as face is set as a strong sensor
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
}
}
@@ -1043,12 +1008,9 @@
faceAuthenticateIsCalled()
}
- private suspend fun TestScope.testGatingCheckForFaceAuth(
- isFaceStrong: Boolean = false,
- gatingCheckModifier: () -> Unit
- ) {
+ private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) {
initCollectors()
- allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
+ allPreconditionsToRunFaceAuthAreTrue()
gatingCheckModifier()
runCurrent()
@@ -1057,7 +1019,7 @@
assertThat(underTest.canRunFaceAuth.value).isFalse()
// flip the gating check back on.
- allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
+ allPreconditionsToRunFaceAuthAreTrue()
triggerFaceAuth(false)
@@ -1076,19 +1038,12 @@
faceAuthenticateIsNotCalled()
}
- private suspend fun TestScope.testGatingCheckForDetect(
- isFaceStrong: Boolean = false,
- gatingCheckModifier: () -> Unit
- ) {
+ private suspend fun TestScope.testGatingCheckForDetect(gatingCheckModifier: () -> Unit) {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
- if (isFaceStrong) {
- biometricSettingsRepository.setStrongBiometricAllowed(false)
- } else {
- // This will stop face auth from running but is required to be false for detect.
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
- }
+ // This will stop face auth from running but is required to be false for detect.
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
runCurrent()
assertThat(canFaceAuthRun()).isFalse()
@@ -1123,13 +1078,9 @@
cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true }
}
- private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue(
- isFaceStrong: Boolean = false
- ) {
+ private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
verify(faceManager, atLeastOnce())
.addLockoutResetCallback(faceLockoutResetCallback.capture())
- biometricSettingsRepository.setFaceEnrolled(true)
- biometricSettingsRepository.setIsFaceAuthEnabled(true)
underTest.resumeFaceAuth()
trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false)
@@ -1140,14 +1091,11 @@
WakeSleepReason.OTHER
)
)
- if (isFaceStrong) {
- biometricSettingsRepository.setStrongBiometricAllowed(true)
- } else {
- biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
- }
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
biometricSettingsRepository.setIsUserInLockdown(false)
fakeUserRepository.setSelectedUserInfo(primaryUser)
- biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
faceLockoutResetCallback.value.onLockoutReset(0)
bouncerRepository.setAlternateVisible(true)
keyguardRepository.setKeyguardShowing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index dcaafe8..6fcf54c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.data.repository
import android.graphics.Point
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
@@ -47,7 +47,7 @@
@SmallTest
@RoboPilotTest
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class LightRevealScrimRepositoryTest : SysuiTestCase() {
private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
private lateinit var underTest: LightRevealScrimRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
new file mode 100644
index 0000000..e0ae0c3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -0,0 +1,297 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import android.media.AudioManager
+import android.media.session.MediaSessionLegacyHelper
+import android.view.KeyEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardKeyEventInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ private val actionDownVolumeDownKeyEvent =
+ KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN)
+ private val actionDownVolumeUpKeyEvent =
+ KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
+ private val backKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
+ private val awakeWakefulnessMode =
+ WakefulnessModel(WakefulnessState.AWAKE, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
+ private val asleepWakefulnessMode =
+ WakefulnessModel(WakefulnessState.ASLEEP, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
+
+ private lateinit var keyguardInteractorWithDependencies:
+ KeyguardInteractorFactory.WithDependencies
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var shadeController: ShadeController
+ @Mock private lateinit var mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper
+ @Mock private lateinit var mediaSessionLegacyHelper: MediaSessionLegacyHelper
+ @Mock private lateinit var backActionInteractor: BackActionInteractor
+
+ private lateinit var underTest: KeyguardKeyEventInteractor
+
+ @Before
+ fun setup() {
+ whenever(mediaSessionLegacyHelperWrapper.getHelper(any()))
+ .thenReturn(mediaSessionLegacyHelper)
+ keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
+ underTest =
+ KeyguardKeyEventInteractor(
+ context,
+ statusBarStateController,
+ keyguardInteractorWithDependencies.keyguardInteractor,
+ statusBarKeyguardViewManager,
+ shadeController,
+ mediaSessionLegacyHelperWrapper,
+ backActionInteractor,
+ )
+ }
+
+ @Test
+ fun dispatchKeyEvent_volumeKey_dozing_handlesEvents() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+
+ assertThat(underTest.dispatchKeyEvent(actionDownVolumeDownKeyEvent)).isTrue()
+ verify(mediaSessionLegacyHelper)
+ .sendVolumeKeyEvent(
+ eq(actionDownVolumeDownKeyEvent),
+ eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
+ eq(true)
+ )
+
+ assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isTrue()
+ verify(mediaSessionLegacyHelper)
+ .sendVolumeKeyEvent(
+ eq(actionDownVolumeUpKeyEvent),
+ eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
+ eq(true)
+ )
+ }
+
+ @Test
+ fun dispatchKeyEvent_volumeKey_notDozing_doesNotHandleEvents() {
+ whenever(statusBarStateController.isDozing).thenReturn(false)
+
+ assertThat(underTest.dispatchKeyEvent(actionDownVolumeDownKeyEvent)).isFalse()
+ verify(mediaSessionLegacyHelper, never())
+ .sendVolumeKeyEvent(
+ eq(actionDownVolumeDownKeyEvent),
+ eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
+ eq(true)
+ )
+
+ assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isFalse()
+ verify(mediaSessionLegacyHelper, never())
+ .sendVolumeKeyEvent(
+ eq(actionDownVolumeUpKeyEvent),
+ eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
+ eq(true)
+ )
+ }
+
+ @Test
+ fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_showsPrimaryBouncer() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
+
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU)
+ }
+
+ @Test
+ fun dispatchKeyEvent_menuActionUp_interactiveShadeLocked_collapsesShade() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
+
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
+ }
+
+ @Test
+ fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_doNothing() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(asleepWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
+
+ verifyActionsDoNothing(KeyEvent.KEYCODE_MENU)
+ }
+
+ @Test
+ fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_showsPrimaryBouncer() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_SPACE)
+ }
+
+ @Test
+ fun dispatchKeyEvent_spaceActionUp_shadeLocked_collapsesShade() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_SPACE)
+ }
+
+ @Test
+ fun dispatchKeyEvent_enterActionUp_interactiveKeyguard_showsPrimaryBouncer() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_ENTER)
+ }
+
+ @Test
+ fun dispatchKeyEvent_enterActionUp_shadeLocked_collapsesShade() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_ENTER)
+ }
+
+ @Test
+ fun dispatchKeyEventPreIme_back_keyguard_onBackRequested() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(true)
+
+ whenever(backActionInteractor.onBackRequested()).thenReturn(false)
+ assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
+ verify(backActionInteractor).onBackRequested()
+ clearInvocations(backActionInteractor)
+
+ whenever(backActionInteractor.onBackRequested()).thenReturn(true)
+ assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isTrue()
+ verify(backActionInteractor).onBackRequested()
+ }
+
+ @Test
+ fun dispatchKeyEventPreIme_back_keyguard_SBKVMdoesNotHandle_neverOnBackRequested() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(false)
+ whenever(backActionInteractor.onBackRequested()).thenReturn(true)
+
+ assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
+ verify(backActionInteractor, never()).onBackRequested()
+ }
+
+ @Test
+ fun dispatchKeyEventPreIme_back_shade_neverOnBackRequested() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(true)
+ whenever(backActionInteractor.onBackRequested()).thenReturn(true)
+
+ assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
+ verify(backActionInteractor, never()).onBackRequested()
+ }
+
+ @Test
+ fun interceptMediaKey_keyguard_SBKVMdoesNotHandle_doesNotHandleMediaKey() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.interceptMediaKey(eq(keyEvent))).thenReturn(false)
+
+ assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
+ verify(statusBarKeyguardViewManager).interceptMediaKey(eq(keyEvent))
+ }
+
+ @Test
+ fun interceptMediaKey_keyguard_handleMediaKey() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(statusBarKeyguardViewManager.interceptMediaKey(eq(keyEvent))).thenReturn(true)
+
+ assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
+ verify(statusBarKeyguardViewManager).interceptMediaKey(eq(keyEvent))
+ }
+
+ @Test
+ fun interceptMediaKey_shade_doesNotHandleMediaKey() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+
+ assertThat(
+ underTest.interceptMediaKey(
+ KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
+ )
+ )
+ .isFalse()
+ verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any())
+ }
+
+ private fun verifyActionUpCollapsesTheShade(keycode: Int) {
+ // action down: does NOT collapse the shade
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+
+ // action up: collapses the shade
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(shadeController).animateCollapseShadeForced()
+ }
+
+ private fun verifyActionUpShowsPrimaryBouncer(keycode: Int) {
+ // action down: does NOT collapse the shade
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+ // action up: collapses the shade
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(statusBarKeyguardViewManager).showPrimaryBouncer(eq(true))
+ }
+
+ private fun verifyActionsDoNothing(keycode: Int) {
+ // action down: does nothing
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+ // action up: doesNothing
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 16cc924..713c602 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -147,16 +147,4 @@
underTest.setVisible(true, "reason")
assertThat(isVisible).isTrue()
}
-
- @Test
- fun remoteUserInput() =
- testScope.runTest {
- val remoteUserInput by collectLastValue(underTest.remoteUserInput)
- assertThat(remoteUserInput).isNull()
-
- for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) {
- underTest.onRemoteUserInput(input)
- assertThat(remoteUserInput).isEqualTo(input)
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index da6c4269..88abb642 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -18,19 +18,14 @@
package com.android.systemui.scene.ui.viewmodel
-import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.model.RemoteUserInput
-import com.android.systemui.scene.shared.model.RemoteUserInputAction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.currentTime
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -73,35 +68,4 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
-
- @Test
- fun onRemoteUserInput() = runTest {
- val remoteUserInput by collectLastValue(underTest.remoteUserInput)
- assertThat(remoteUserInput).isNull()
-
- val inputs =
- SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE.map { remoteUserInputToMotionEvent(it) }
-
- inputs.forEachIndexed { index, input ->
- underTest.onRemoteUserInput(input)
- assertThat(remoteUserInput).isEqualTo(SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE[index])
- }
- }
-
- private fun TestScope.remoteUserInputToMotionEvent(input: RemoteUserInput): MotionEvent {
- return MotionEvent.obtain(
- currentTime,
- currentTime,
- when (input.action) {
- RemoteUserInputAction.DOWN -> MotionEvent.ACTION_DOWN
- RemoteUserInputAction.MOVE -> MotionEvent.ACTION_MOVE
- RemoteUserInputAction.UP -> MotionEvent.ACTION_UP
- RemoteUserInputAction.CANCEL -> MotionEvent.ACTION_CANCEL
- RemoteUserInputAction.UNKNOWN -> MotionEvent.ACTION_OUTSIDE
- },
- input.x,
- input.y,
- 0
- )
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
index 2d3ee0e..ca4486b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -20,12 +20,13 @@
import android.content.Context
import android.content.Intent
import android.net.Uri
-import androidx.test.ext.truth.content.IntentSubject.assertThat
+import androidx.test.ext.truth.content.IntentSubject.assertThat as assertThatIntent
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
import org.mockito.Mockito.`when` as whenever
@@ -39,23 +40,23 @@
val output = ActionIntentCreator.createShare(uri)
- assertThat(output).hasAction(Intent.ACTION_CHOOSER)
- assertThat(output)
+ assertThatIntent(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThatIntent(output)
.hasFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
- assertThat(output).extras().parcelable<Intent>(Intent.EXTRA_INTENT).isNotNull()
+ assertThatIntent(output).extras().parcelable<Intent>(Intent.EXTRA_INTENT).isNotNull()
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
- assertThat(wrappedIntent).hasData(uri)
- assertThat(wrappedIntent).hasType("image/png")
- assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
- assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
- assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
+ assertThatIntent(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThatIntent(wrappedIntent).hasData(uri)
+ assertThatIntent(wrappedIntent).hasType("image/png")
+ assertThatIntent(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
+ assertThatIntent(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
+ assertThatIntent(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
@@ -64,7 +65,7 @@
val output = ActionIntentCreator.createShare(uri)
- assertThat(output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java))
+ assertThatIntent(output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java))
.hasData(Uri.parse("content://fake"))
}
@@ -75,8 +76,8 @@
val output = ActionIntentCreator.createShareWithSubject(uri, subject)
- assertThat(output).hasAction(Intent.ACTION_CHOOSER)
- assertThat(output)
+ assertThatIntent(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThatIntent(output)
.hasFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK or
@@ -84,12 +85,12 @@
)
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
- assertThat(wrappedIntent).hasData(uri)
- assertThat(wrappedIntent).hasType("image/png")
- assertThat(wrappedIntent).extras().string(Intent.EXTRA_SUBJECT).isEqualTo(subject)
- assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
- assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
+ assertThatIntent(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThatIntent(wrappedIntent).hasData(uri)
+ assertThatIntent(wrappedIntent).hasType("image/png")
+ assertThatIntent(wrappedIntent).extras().string(Intent.EXTRA_SUBJECT).isEqualTo(subject)
+ assertThatIntent(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
+ assertThatIntent(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
@@ -99,8 +100,8 @@
val output = ActionIntentCreator.createShareWithText(uri, extraText)
- assertThat(output).hasAction(Intent.ACTION_CHOOSER)
- assertThat(output)
+ assertThatIntent(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThatIntent(output)
.hasFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK or
@@ -108,12 +109,12 @@
)
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
- assertThat(wrappedIntent).hasData(uri)
- assertThat(wrappedIntent).hasType("image/png")
- assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
- assertThat(wrappedIntent).extras().string(Intent.EXTRA_TEXT).isEqualTo(extraText)
- assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
+ assertThatIntent(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThatIntent(wrappedIntent).hasData(uri)
+ assertThatIntent(wrappedIntent).hasType("image/png")
+ assertThatIntent(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
+ assertThatIntent(wrappedIntent).extras().string(Intent.EXTRA_TEXT).isEqualTo(extraText)
+ assertThatIntent(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
@@ -125,11 +126,12 @@
val output = ActionIntentCreator.createEdit(uri, context)
- assertThat(output).hasAction(Intent.ACTION_EDIT)
- assertThat(output).hasData(uri)
- assertThat(output).hasType("image/png")
+ assertThatIntent(output).hasAction(Intent.ACTION_EDIT)
+ assertThatIntent(output).hasData(uri)
+ assertThatIntent(output).hasType("image/png")
assertWithMessage("getComponent()").that(output.component).isNull()
- assertThat(output)
+ assertThat(output.getStringExtra("edit_source")).isEqualTo("screenshot")
+ assertThatIntent(output)
.hasFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
@@ -146,7 +148,7 @@
val output = ActionIntentCreator.createEdit(uri, context)
- assertThat(output).hasData(Uri.parse("content://fake"))
+ assertThatIntent(output).hasData(Uri.parse("content://fake"))
}
@Test
@@ -160,6 +162,6 @@
val output = ActionIntentCreator.createEdit(uri, context)
- assertThat(output).hasComponent(component)
+ assertThatIntent(output).hasComponent(component)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index eb4ae1a..7aeafeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -539,6 +539,23 @@
}
@Test
+ public void onKeyguardStatusViewHeightChange_animatesNextTopPaddingChangeForNSSL() {
+ ArgumentCaptor<View.OnLayoutChangeListener> captor =
+ ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+ verify(mKeyguardStatusView).addOnLayoutChangeListener(captor.capture());
+ View.OnLayoutChangeListener listener = captor.getValue();
+
+ clearInvocations(mNotificationStackScrollLayoutController);
+
+ when(mKeyguardStatusView.getHeight()).thenReturn(0);
+ listener.onLayoutChange(mKeyguardStatusView, /* left= */ 0, /* top= */ 0, /* right= */
+ 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
+ 0, /* oldBottom = */ 200);
+
+ verify(mNotificationStackScrollLayoutController).animateNextTopPaddingChange();
+ }
+
+ @Test
public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
mStatusBarStateController.setState(KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 1edeeff..3cce423 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -18,6 +18,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.view.KeyEvent
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -118,8 +120,10 @@
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
+ @Mock lateinit var keyEventInteractor: KeyEventInteractor
private val notificationExpansionRepository = NotificationExpansionRepository()
+ private lateinit var fakeClock: FakeSystemClock
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -148,6 +152,7 @@
featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
testScope = TestScope()
+ fakeClock = FakeSystemClock()
underTest =
NotificationShadeWindowViewController(
lockscreenShadeTransitionController,
@@ -180,7 +185,7 @@
primaryBouncerToGoneTransitionViewModel,
notificationExpansionRepository,
featureFlags,
- FakeSystemClock(),
+ fakeClock,
BouncerMessageInteractor(
FakeBouncerMessageRepository(),
mock(BouncerMessageFactory::class.java),
@@ -188,7 +193,8 @@
CountDownTimerUtil(),
featureFlags
),
- BouncerLogger(logcatLogBuffer("BouncerLog"))
+ BouncerLogger(logcatLogBuffer("BouncerLog")),
+ keyEventInteractor,
)
underTest.setupExpandedStatusBar()
@@ -328,6 +334,33 @@
}
@Test
+ fun handleDispatchTouchEvent_launchAnimationRunningTimesOut() =
+ testScope.runTest {
+ // GIVEN touch dispatcher in a state that returns true
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(
+ true
+ )
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+
+ // WHEN launch animation is running for 2 seconds
+ fakeClock.setUptimeMillis(10000)
+ underTest.setExpandAnimationRunning(true)
+ fakeClock.advanceTime(2000)
+
+ // THEN touch is ignored
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isFalse()
+
+ // WHEN Launch animation is running for 6 seconds
+ fakeClock.advanceTime(4000)
+
+ // THEN move is ignored, down is handled, and window is notified
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(MOVE_EVENT)).isFalse()
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+ verify(notificationShadeWindowController).setLaunchingActivity(false)
+ }
+
+ @Test
fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
// down event should be intercepted by keyguardViewManager
whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
@@ -345,8 +378,30 @@
verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
}
+ @Test
+ fun forwardsDispatchKeyEvent() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+ interactionEventHandler.dispatchKeyEvent(keyEvent)
+ verify(keyEventInteractor).dispatchKeyEvent(keyEvent)
+ }
+
+ @Test
+ fun forwardsDispatchKeyEventPreIme() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+ interactionEventHandler.dispatchKeyEventPreIme(keyEvent)
+ verify(keyEventInteractor).dispatchKeyEventPreIme(keyEvent)
+ }
+
+ @Test
+ fun forwardsInterceptMediaKey() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
+ interactionEventHandler.interceptMediaKey(keyEvent)
+ verify(keyEventInteractor).interceptMediaKey(keyEvent)
+ }
+
companion object {
private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
private const val VIEW_BOTTOM = 100
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 829184c..66d48d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
@@ -198,7 +199,8 @@
CountDownTimerUtil(),
featureFlags
),
- BouncerLogger(logcatLogBuffer("BouncerLog"))
+ BouncerLogger(logcatLogBuffer("BouncerLog")),
+ Mockito.mock(KeyEventInteractor::class.java),
)
controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 31bfa3fd..5fa6b3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -50,6 +51,12 @@
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -61,6 +68,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -95,6 +106,18 @@
private TestableLooper mTestableLooper;
@Mock
private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+ @Mock
+ private MobileUiAdapter mMobileUiAdapter;
+ @Mock
+ private MobileIconsViewModel mMobileIconsViewModel;
+ @Mock
+ private ShadeCarrierGroupMobileIconViewModel mShadeCarrierGroupMobileIconViewModel;
+ @Mock
+ private MobileViewLogger mMobileViewLogger;
+ @Mock
+ private MobileContextProvider mMobileContextProvider;
+ @Mock
+ private StatusBarPipelineFlags mStatusBarPipelineFlags;
private FakeSlotIndexResolver mSlotIndexResolver;
private ClickListenerTextView mNoCarrierTextView;
@@ -133,16 +156,35 @@
mSlotIndexResolver = new FakeSlotIndexResolver();
+ when(mMobileUiAdapter.getMobileIconsViewModel()).thenReturn(mMobileIconsViewModel);
+
mShadeCarrierGroupController = new ShadeCarrierGroupController.Builder(
- mActivityStarter, handler, TestableLooper.get(this).getLooper(),
- mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
- mSlotIndexResolver)
+ mActivityStarter,
+ handler,
+ TestableLooper.get(this).getLooper(),
+ mNetworkController,
+ mCarrierTextControllerBuilder,
+ mContext,
+ mCarrierConfigTracker,
+ mSlotIndexResolver,
+ mMobileUiAdapter,
+ mMobileContextProvider,
+ mStatusBarPipelineFlags
+ )
.setShadeCarrierGroup(mShadeCarrierGroup)
.build();
mShadeCarrierGroupController.setListening(true);
}
+ private void setupWithNewPipeline() {
+ when(mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()).thenReturn(true);
+ when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
+ when(mMobileIconsViewModel.getLogger()).thenReturn(mMobileViewLogger);
+ when(mMobileIconsViewModel.viewModelForSub(anyInt(), any()))
+ .thenReturn(mShadeCarrierGroupMobileIconViewModel);
+ }
+
@Test
public void testInitiallyMultiCarrier() {
assertFalse(mShadeCarrierGroupController.isSingleCarrier());
@@ -406,6 +448,129 @@
verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
}
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_addSubscription() {
+ setupWithNewPipeline();
+
+ mShadeCarrier1.setVisibility(View.GONE);
+ mShadeCarrier2.setVisibility(View.GONE);
+ mShadeCarrier3.setVisibility(View.GONE);
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.add(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1, times(1)).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_removeSubscription() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ subIds.add(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.remove(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1, times(1)).removeModernMobileView();
+ verify(mShadeCarrier2, times(1)).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_removeSubscriptionOutOfOrder() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ subIds.add(1);
+ subIds.add(2);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.remove(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).removeModernMobileView();
+ verify(mShadeCarrier2).removeModernMobileView();
+ verify(mShadeCarrier3).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_moreSubsThanSimSlots_listLimitedToMax() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 1, 2, 2);
+
+ assertThat(mShadeCarrierGroupController.processSubIdList(subIds).size()).isEqualTo(3);
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_invalidSimSlotIndexFilteredOut() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 1, -1);
+
+ List<ShadeCarrierGroupController.IconData> processedSubs =
+ mShadeCarrierGroupController.processSubIdList(subIds);
+ assertThat(processedSubs).hasSize(2);
+ assertThat(processedSubs.get(0).subId).isNotEqualTo(-1);
+ assertThat(processedSubs.get(1).subId).isNotEqualTo(-1);
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_indexGreaterThanSimSlotsFilteredOut() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 4);
+
+ List<ShadeCarrierGroupController.IconData> processedSubs =
+ mShadeCarrierGroupController.processSubIdList(subIds);
+ assertThat(processedSubs).hasSize(1);
+ assertThat(processedSubs.get(0).subId).isNotEqualTo(4);
+ }
+
+
@Test
public void testOnlyInternalViewsHaveClickableListener() {
ArgumentCaptor<View.OnClickListener> captor =
@@ -447,6 +612,12 @@
.isEqualTo(Settings.ACTION_WIRELESS_SETTINGS);
}
+ private void resetShadeCarriers() {
+ reset(mShadeCarrier1);
+ reset(mShadeCarrier2);
+ reset(mShadeCarrier3);
+ }
+
private class FakeSlotIndexResolver implements ShadeCarrierGroupController.SlotIndexResolver {
public boolean overrideInvalid;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 9495fdd..ecaf137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -227,6 +227,25 @@
}
@Test
+ fun activeClockId_changeAfterPluginConnected() {
+ val plugin1 = FakeClockPlugin()
+ .addClock("clock_1", "clock 1")
+ .addClock("clock_2", "clock 2")
+
+ val plugin2 = FakeClockPlugin()
+ .addClock("clock_3", "clock 3", { mockClock })
+ .addClock("clock_4", "clock 4")
+
+ registry.applySettings(ClockSettings("clock_3", null))
+
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+ assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId)
+
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+ assertEquals("clock_3", registry.activeClockId)
+ }
+
+ @Test
fun createDefaultClock_pluginDisconnected() {
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index 4a94dc8..38a8f414 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -21,11 +21,21 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
import org.junit.Assert
import org.junit.Before
import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -36,13 +46,43 @@
private val groupMembershipManager: GroupMembershipManager = mock()
private val featureFlags = FakeFeatureFlags()
- private val entry1 = NotificationEntryBuilder().build()
- private val entry2 = NotificationEntryBuilder().build()
+ private val pipeline: NotifPipeline = mock()
+ private lateinit var beforeRenderListListener: OnBeforeRenderListListener
+
+ private val summary1 = notificationEntry("foo", 1)
+ private val summary2 = notificationEntry("bar", 1)
+ private val entries =
+ listOf<ListEntry>(
+ GroupEntryBuilder()
+ .setSummary(summary1)
+ .setChildren(
+ listOf(
+ notificationEntry("foo", 2),
+ notificationEntry("foo", 3),
+ notificationEntry("foo", 4)
+ )
+ )
+ .build(),
+ GroupEntryBuilder()
+ .setSummary(summary2)
+ .setChildren(
+ listOf(
+ notificationEntry("bar", 2),
+ notificationEntry("bar", 3),
+ notificationEntry("bar", 4)
+ )
+ )
+ .build(),
+ notificationEntry("baz", 1)
+ )
+
+ private fun notificationEntry(pkg: String, id: Int) =
+ NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply { row = mock() }
@Before
fun setUp() {
- whenever(groupMembershipManager.getGroupSummary(entry1)).thenReturn(entry1)
- whenever(groupMembershipManager.getGroupSummary(entry2)).thenReturn(entry2)
+ whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
+ whenever(groupMembershipManager.getGroupSummary(summary2)).thenReturn(summary2)
gem = GroupExpansionManagerImpl(dumpManager, groupMembershipManager, featureFlags)
}
@@ -54,15 +94,15 @@
var listenerCalledCount = 0
gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
- gem.setGroupExpanded(entry1, false)
+ gem.setGroupExpanded(summary1, false)
Assert.assertEquals(0, listenerCalledCount)
- gem.setGroupExpanded(entry1, true)
+ gem.setGroupExpanded(summary1, true)
Assert.assertEquals(1, listenerCalledCount)
- gem.setGroupExpanded(entry2, true)
+ gem.setGroupExpanded(summary2, true)
Assert.assertEquals(2, listenerCalledCount)
- gem.setGroupExpanded(entry1, true)
+ gem.setGroupExpanded(summary1, true)
Assert.assertEquals(2, listenerCalledCount)
- gem.setGroupExpanded(entry2, false)
+ gem.setGroupExpanded(summary2, false)
Assert.assertEquals(3, listenerCalledCount)
}
@@ -73,15 +113,39 @@
var listenerCalledCount = 0
gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
- gem.setGroupExpanded(entry1, false)
+ gem.setGroupExpanded(summary1, false)
Assert.assertEquals(1, listenerCalledCount)
- gem.setGroupExpanded(entry1, true)
+ gem.setGroupExpanded(summary1, true)
Assert.assertEquals(2, listenerCalledCount)
- gem.setGroupExpanded(entry2, true)
+ gem.setGroupExpanded(summary2, true)
Assert.assertEquals(3, listenerCalledCount)
- gem.setGroupExpanded(entry1, true)
+ gem.setGroupExpanded(summary1, true)
Assert.assertEquals(4, listenerCalledCount)
- gem.setGroupExpanded(entry2, false)
+ gem.setGroupExpanded(summary2, false)
Assert.assertEquals(5, listenerCalledCount)
}
+
+ @Test
+ fun testSyncWithPipeline() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+ gem.attach(pipeline)
+ beforeRenderListListener = withArgCaptor {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ val listener: OnGroupExpansionChangeListener = mock()
+ gem.registerGroupExpansionChangeListener(listener)
+
+ beforeRenderListListener.onBeforeRenderList(entries)
+ verify(listener, never()).onGroupExpansionChange(any(), any())
+
+ // Expand one of the groups.
+ gem.setGroupExpanded(summary1, true)
+ verify(listener).onGroupExpansionChange(summary1.row, true)
+
+ // Empty the pipeline list and verify that the group is no longer expanded.
+ beforeRenderListListener.onBeforeRenderList(emptyList())
+ verify(listener).onGroupExpansionChange(summary1.row, false)
+ verifyNoMoreInteractions(listener)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
new file mode 100644
index 0000000..b8792a8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.statusbar.notification.icon.ui.viewbinder
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {
+ @Mock private lateinit var notifListener: NotificationListener
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var wakeUpCoordinator: NotificationWakeUpCoordinator
+ @Mock private lateinit var keyguardBypassController: KeyguardBypassController
+ @Mock private lateinit var notifMediaManager: NotificationMediaManager
+ @Mock private lateinit var dozeParams: DozeParameters
+ @Mock private lateinit var sectionStyleProvider: SectionStyleProvider
+ @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
+ @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+ @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
+ @Mock private lateinit var bubbles: Bubbles
+ @Mock private lateinit var demoModeController: DemoModeController
+ @Mock private lateinit var aodIcons: NotificationIconContainer
+ @Mock private lateinit var featureFlags: FeatureFlags
+
+ private val shelfViewModel = NotificationIconContainerShelfViewModel()
+ private val statusBarViewModel = NotificationIconContainerStatusBarViewModel()
+ private val aodViewModel = NotificationIconContainerAlwaysOnDisplayViewModel()
+
+ private lateinit var underTest: NotificationIconAreaControllerViewBinderWrapperImpl
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ NotificationIconAreaControllerViewBinderWrapperImpl(
+ mContext,
+ statusBarStateController,
+ wakeUpCoordinator,
+ keyguardBypassController,
+ notifMediaManager,
+ notifListener,
+ dozeParams,
+ sectionStyleProvider,
+ Optional.of(bubbles),
+ demoModeController,
+ darkIconDispatcher,
+ featureFlags,
+ statusBarWindowController,
+ screenOffAnimController,
+ shelfViewModel,
+ statusBarViewModel,
+ aodViewModel,
+ )
+ }
+
+ @Test
+ fun testNotificationIcons_settingHideIcons() {
+ underTest.settingsListener.onStatusBarIconsBehaviorChanged(true)
+ assertFalse(underTest.shouldShowLowPriorityIcons())
+ }
+
+ @Test
+ fun testNotificationIcons_settingShowIcons() {
+ underTest.settingsListener.onStatusBarIconsBehaviorChanged(false)
+ assertTrue(underTest.shouldShowLowPriorityIcons())
+ }
+
+ @Test
+ fun testAppearResetsTranslation() {
+ underTest.setupAodIcons(aodIcons)
+ whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+ underTest.appearAodIcons()
+ verify(aodIcons).translationY = 0f
+ verify(aodIcons).alpha = 1.0f
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 8545b89..3ad3c15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -18,6 +18,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
+
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -29,8 +31,10 @@
import android.app.StatusBarManager;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.os.VibrationEffect;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
+import android.view.HapticFeedbackConstants;
import android.view.WindowInsets;
import androidx.test.filters.SmallTest;
@@ -42,6 +46,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSHost;
@@ -98,6 +103,7 @@
@Mock private UserTracker mUserTracker;
@Mock private QSHost mQSHost;
@Mock private ActivityStarter mActivityStarter;
+ private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
CentralSurfacesCommandQueueCallbacks mSbcqCallbacks;
@@ -134,7 +140,8 @@
mCameraLauncherLazy,
mUserTracker,
mQSHost,
- mActivityStarter);
+ mActivityStarter,
+ mFeatureFlags);
when(mUserTracker.getUserHandle()).thenReturn(
UserHandle.of(ActivityManager.getCurrentUser()));
@@ -241,4 +248,24 @@
verifyZeroInteractions(mSystemBarAttributesListener);
}
+
+ @Test
+ public void vibrateOnNavigationKeyDown_oneWayHapticsDisabled_usesVibrate() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false);
+
+ mSbcqCallbacks.vibrateOnNavigationKeyDown();
+
+ verify(mVibratorHelper).vibrate(VibrationEffect.EFFECT_TICK);
+ }
+
+ @Test
+ public void vibrateOnNavigationKeyDown_oneWayHapticsEnabled_usesPerformHapticFeedback() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+
+ mSbcqCallbacks.vibrateOnNavigationKeyDown();
+
+ verify(mShadeViewController).performHapticFeedback(
+ HapticFeedbackConstants.GESTURE_START
+ );
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 8e1dcf0..1b8cfd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -48,7 +48,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class NotificationIconAreaControllerTest extends SysuiTestCase {
+public class LegacyNotificationIconAreaControllerImplTest extends SysuiTestCase {
@Mock
private NotificationListener mListener;
@@ -70,7 +70,7 @@
StatusBarWindowController mStatusBarWindowController;
@Mock
ScreenOffAnimationController mScreenOffAnimationController;
- private NotificationIconAreaController mController;
+ private LegacyNotificationIconAreaControllerImpl mController;
@Mock
private Bubbles mBubbles;
@Mock private DemoModeController mDemoModeController;
@@ -82,7 +82,7 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mController = new NotificationIconAreaController(
+ mController = new LegacyNotificationIconAreaControllerImpl(
mContext,
mStatusBarStateController,
mWakeUpCoordinator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 2e92bb9..0b31523 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -27,7 +27,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeControllerImpl
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
@@ -77,7 +77,7 @@
@Mock
private lateinit var shadeControllerImpl: ShadeControllerImpl
@Mock
- private lateinit var sceneInteractor: Provider<SceneInteractor>
+ private lateinit var windowRootView: Provider<WindowRootView>
@Mock
private lateinit var shadeLogger: ShadeLogger
@Mock
@@ -203,7 +203,7 @@
centralSurfacesImpl,
shadeControllerImpl,
shadeViewController,
- sceneInteractor,
+ windowRootView,
shadeLogger,
viewUtil,
configurationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0dc1d9a..6b3bd22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1802,6 +1802,15 @@
assertFalse(ScrimState.UNLOCKED.mAnimateChange);
}
+ @Test
+ public void testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ when(mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(true);
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.onUnlockAnimationFinished();
+ assertAlphaAfterExpansion(mNotificationsScrim, 1f, 1f);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 823155b..b8f2cab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -81,7 +81,7 @@
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
-import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -136,8 +136,8 @@
private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @ClassRule
- public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+ @Rule
+ public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
private List<StatusBarWindowStateListener> mStatusBarWindowStateListeners = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 50ee6a3..ff28753 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -52,12 +52,19 @@
override val cdmaRoaming = MutableStateFlow(false)
- override val networkName =
- MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
+ override val networkName: MutableStateFlow<NetworkNameModel> =
+ MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
+
+ override val carrierName: MutableStateFlow<NetworkNameModel> =
+ MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
+
+ companion object {
+ const val DEFAULT_NETWORK_NAME = "default name"
+ }
}
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 3591c17..99e4030 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
@@ -75,7 +75,11 @@
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId]
- ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
+ ?: FakeMobileConnectionRepository(
+ subId,
+ tableLogBuffer,
+ )
+ .also { subIdRepos[subId] = it }
}
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 5a887eb..d005972 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -243,13 +243,29 @@
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1
+ private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val SUB_1 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
- private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+ whenever(it.carrierName).thenReturn(SUB_1_NAME)
+ }
+ private val MODEL_1 =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = SUB_1_NAME,
+ )
private const val SUB_2_ID = 2
+ private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val SUB_2 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
- private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+ whenever(it.carrierName).thenReturn(SUB_2_NAME)
+ }
+ private val MODEL_2 =
+ SubscriptionModel(
+ subscriptionId = SUB_2_ID,
+ carrierName = SUB_2_NAME,
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 7573b28..57f97ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -38,7 +38,6 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -140,6 +139,7 @@
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
+ launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -163,6 +163,8 @@
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
+ assertThat(conn.carrierName.value)
+ .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387): check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()
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 efaf152..2712b70 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
@@ -546,6 +546,7 @@
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
+ launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -571,6 +572,8 @@
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
+ assertThat(conn.carrierName.value)
+ .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387) check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 3dd2eaf..9c0cb17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
@@ -43,6 +44,7 @@
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -79,28 +81,51 @@
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
+ private val subscriptionModel =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
private lateinit var mobileRepo: FakeMobileConnectionRepository
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
@Before
fun setUp() {
- mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+ mobileRepo =
+ FakeMobileConnectionRepository(
+ SUB_ID,
+ tableLogBuffer,
+ )
carrierMergedRepo =
- FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
- // Mimicks the real carrier merged repository
- this.isAllowedDuringAirplaneMode.value = true
- }
+ FakeMobileConnectionRepository(
+ SUB_ID,
+ tableLogBuffer,
+ )
+ .apply {
+ // Mimicks the real carrier merged repository
+ this.isAllowedDuringAirplaneMode.value = true
+ }
whenever(
mobileFactory.build(
eq(SUB_ID),
any(),
- eq(DEFAULT_NAME),
+ any(),
+ eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
.thenReturn(mobileRepo)
- whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(carrierMergedRepo)
+ whenever(
+ carrierMergedFactory.build(
+ eq(SUB_ID),
+ any(),
+ )
+ )
+ .thenReturn(carrierMergedRepo)
}
@Test
@@ -120,7 +145,8 @@
.build(
SUB_ID,
tableLogBuffer,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
}
@@ -138,7 +164,11 @@
assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
- verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
+ verify(carrierMergedFactory, never())
+ .build(
+ SUB_ID,
+ tableLogBuffer,
+ )
}
@Test
@@ -348,7 +378,8 @@
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -356,7 +387,8 @@
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -388,7 +420,8 @@
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -397,7 +430,8 @@
factory.build(
SUB_ID,
startingIsCarrierMerged = true,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -623,7 +657,8 @@
SUB_ID,
startingIsCarrierMerged,
tableLogBuffer,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
testScope.backgroundScope,
mobileFactory,
@@ -639,8 +674,9 @@
val realRepo =
MobileConnectionRepositoryImpl(
SUB_ID,
- defaultNetworkName = NetworkNameModel.Default("default"),
- networkNameSeparator = SEP,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
+ SEP,
telephonyManager,
systemUiCarrierConfig = mock(),
fakeBroadcastDispatcher,
@@ -654,7 +690,8 @@
mobileFactory.build(
eq(SUB_ID),
any(),
- eq(DEFAULT_NAME),
+ any(),
+ eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
@@ -677,7 +714,13 @@
testScope.backgroundScope,
wifiRepository,
)
- whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(realRepo)
+ whenever(
+ carrierMergedFactory.build(
+ eq(SUB_ID),
+ any(),
+ )
+ )
+ .thenReturn(realRepo)
return realRepo
}
@@ -690,7 +733,8 @@
private companion object {
const val SUB_ID = 42
- private val DEFAULT_NAME = NetworkNameModel.Default("default name")
+ private val DEFAULT_NAME = "default name"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private const val SEP = "-"
private const val BUFFER_SEPARATOR = "|"
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 1ff737b..e50e5e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -62,6 +62,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
@@ -78,6 +79,7 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -109,6 +111,14 @@
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
+ private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -119,7 +129,8 @@
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
telephonyManager,
systemUiCarrierConfig,
@@ -179,6 +190,7 @@
// gsmLevel updates, no change to cdmaLevel
strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
assertThat(latest).isEqualTo(2)
@@ -638,12 +650,51 @@
}
@Test
+ fun networkNameForSubId_updates() =
+ testScope.runTest {
+ var latest: NetworkNameModel? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ subscriptionModel.value =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+
+ assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+ val updatedName = "Derived Carrier"
+ subscriptionModel.value =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = updatedName,
+ )
+
+ assertThat(latest?.name).isEqualTo(updatedName)
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkNameForSubId_defaultWhenSubscriptionModelNull() =
+ testScope.runTest {
+ var latest: NetworkNameModel? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ subscriptionModel.value = null
+
+ assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+ job.cancel()
+ }
+
+ @Test
fun networkName_default() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(DEFAULT_NAME)
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -701,7 +752,7 @@
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intentWithoutInfo)
- assertThat(latest).isEqualTo(DEFAULT_NAME)
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -852,8 +903,9 @@
companion object {
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = NetworkNameModel.Default("default name")
- private const val SEP = "-"
+ private val DEFAULT_NAME = "Fake Mobile Network"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+ private val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index 4f15aed..ea60aa7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
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.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -47,6 +48,7 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -97,6 +99,7 @@
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
+ @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
private val mobileMappings = FakeMobileMappingsProxy()
private val systemUiCarrierConfig =
@@ -113,11 +116,16 @@
MockitoAnnotations.initMocks(this)
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
- connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
+ connectionsRepo =
+ FakeMobileConnectionsRepository(
+ mobileMappings,
+ tableLogger,
+ )
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
+ subscriptionModel,
DEFAULT_NAME,
SEP,
telephonyManager,
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 c8b6f13d..fd05cc4 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
@@ -1190,30 +1190,36 @@
companion object {
// Subscription 1
private const val SUB_1_ID = 1
+ private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val GROUP_1 = ParcelUuid(UUID.randomUUID())
private val SUB_1 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.groupUuid).thenReturn(GROUP_1)
+ whenever(it.carrierName).thenReturn(SUB_1_NAME)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
groupUuid = GROUP_1,
+ carrierName = SUB_1_NAME,
)
// Subscription 2
private const val SUB_2_ID = 2
+ private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val GROUP_2 = ParcelUuid(UUID.randomUUID())
private val SUB_2 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.groupUuid).thenReturn(GROUP_2)
+ whenever(it.carrierName).thenReturn(SUB_2_NAME)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
groupUuid = GROUP_2,
+ carrierName = SUB_2_NAME,
)
// Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1242,9 +1248,14 @@
// Carrier merged subscription
private const val SUB_CM_ID = 5
+ private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
private val SUB_CM =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
- private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
+ whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+ }
+ private val MODEL_CM =
+ SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
private val WIFI_INFO_CM =
mock<WifiInfo>().apply {
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 8d1da69..a3df785 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
@@ -44,6 +44,8 @@
override val mobileIsDefault = MutableStateFlow(true)
+ override val isSingleCarrier = MutableStateFlow(true)
+
override val networkTypeIconGroup =
MutableStateFlow<NetworkTypeIconModel>(
NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
@@ -51,6 +53,8 @@
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo mode"))
+ override val carrierName = MutableStateFlow("demo mode")
+
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly
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 b2bbcfd..82b7ec4 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
@@ -64,6 +64,8 @@
override val mobileIsDefault = MutableStateFlow(false)
+ override val isSingleCarrier = MutableStateFlow(true)
+
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
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 58d3804..e3c59ad 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
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
@@ -40,6 +41,7 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -56,6 +58,15 @@
private lateinit var underTest: MobileIconInteractor
private val mobileMappingsProxy = FakeMobileMappingsProxy()
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+
+ private val subscriptionModel =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock())
private val testDispatcher = UnconfinedTestDispatcher()
@@ -432,7 +443,7 @@
}
@Test
- fun networkName_usesOperatorAlphaShotWhenNonNullAndRepoIsDefault() =
+ fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -440,7 +451,7 @@
val testOperatorName = "operatorAlphaShort"
// Default network name, operator name is non-null, uses the operator name
- connectionRepository.networkName.value = DEFAULT_NAME
+ connectionRepository.networkName.value = DEFAULT_NAME_MODEL
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
@@ -448,10 +459,39 @@
// Default network name, operator name is null, uses the default
connectionRepository.operatorAlphaShort.value = null
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+ // Derived network name, operator name non-null, uses the derived name
+ connectionRepository.networkName.value = DERIVED_NAME_MODEL
+ connectionRepository.operatorAlphaShort.value = testOperatorName
+
+ assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
+ testScope.runTest {
+ var latest: String? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ val testOperatorName = "operatorAlphaShort"
+
+ // Default network name, operator name is non-null, uses the operator name
+ connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
+ connectionRepository.operatorAlphaShort.value = testOperatorName
+
+ assertThat(latest).isEqualTo(testOperatorName)
+
+ // Default network name, operator name is null, uses the default
+ connectionRepository.operatorAlphaShort.value = null
+
assertThat(latest).isEqualTo(DEFAULT_NAME)
// Derived network name, operator name non-null, uses the derived name
- connectionRepository.networkName.value = DERIVED_NAME
+ connectionRepository.carrierName.value =
+ NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(DERIVED_NAME)
@@ -460,6 +500,21 @@
}
@Test
+ fun isSingleCarrier_matchesParent() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ mobileIconsInteractor.isSingleCarrier.value = true
+ assertThat(latest).isTrue()
+
+ mobileIconsInteractor.isSingleCarrier.value = false
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun isForceHidden_matchesParent() =
testScope.runTest {
var latest: Boolean? = null
@@ -494,6 +549,7 @@
mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.alwaysShowDataRatIcon,
mobileIconsInteractor.alwaysUseCdmaLevel,
+ mobileIconsInteractor.isSingleCarrier,
mobileIconsInteractor.mobileIsDefault,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
@@ -510,7 +566,9 @@
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
- private val DERIVED_NAME = NetworkNameModel.IntentDerived("test derived name")
+ private val DEFAULT_NAME = "test default name"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+ private val DERIVED_NAME = "test derived name"
+ private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
}
}
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 1fb76b0..3e6f909 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
@@ -527,6 +527,57 @@
}
@Test
+ fun isSingleCarrier_zeroSubscriptions_false() =
+ testScope.runTest {
+ var latest: Boolean? = true
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(emptyList())
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_oneSubscription_true() =
+ testScope.runTest {
+ var latest: Boolean? = false
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1))
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_twoSubscriptions_false() =
+ testScope.runTest {
+ var latest: Boolean? = true
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_updates() =
+ testScope.runTest {
+ var latest: Boolean? = false
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1))
+ assertThat(latest).isTrue()
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
testScope.runTest {
var latest: Boolean? = null
@@ -745,6 +796,7 @@
subscriptionId = subscriptionIds.first,
isOpportunistic = opportunistic.first,
groupUuid = groupUuid,
+ carrierName = "Carrier ${subscriptionIds.first}"
)
val sub2 =
@@ -752,6 +804,7 @@
subscriptionId = subscriptionIds.second,
isOpportunistic = opportunistic.second,
groupUuid = groupUuid,
+ carrierName = "Carrier ${opportunistic.second}"
)
return Pair(sub1, sub2)
@@ -760,11 +813,13 @@
companion object {
private const val SUB_1_ID = 1
- private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ private val SUB_1 =
+ SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
private const val SUB_2_ID = 2
- private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ private val SUB_2 =
+ SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
private const val SUB_3_ID = 3
@@ -773,6 +828,7 @@
subscriptionId = SUB_3_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
+ carrierName = "Carrier $SUB_3_ID"
)
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
@@ -782,6 +838,7 @@
subscriptionId = SUB_4_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
+ carrierName = "Carrier $SUB_4_ID"
)
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f0458fa..065dfba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -92,15 +92,31 @@
interactor.filteredSubscriptions.value =
listOf(
- SubscriptionModel(subscriptionId = 1, isOpportunistic = false),
+ SubscriptionModel(
+ subscriptionId = 1,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ ),
)
assertThat(latest).isEqualTo(listOf(1))
interactor.filteredSubscriptions.value =
listOf(
- SubscriptionModel(subscriptionId = 2, isOpportunistic = false),
- SubscriptionModel(subscriptionId = 5, isOpportunistic = true),
- SubscriptionModel(subscriptionId = 7, isOpportunistic = true),
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = false,
+ carrierName = "Carrier 2",
+ ),
+ SubscriptionModel(
+ subscriptionId = 5,
+ isOpportunistic = true,
+ carrierName = "Carrier 5",
+ ),
+ SubscriptionModel(
+ subscriptionId = 7,
+ isOpportunistic = true,
+ carrierName = "Carrier 7",
+ ),
)
assertThat(latest).isEqualTo(listOf(2, 5, 7))
@@ -138,6 +154,33 @@
}
@Test
+ fun caching_mobileIconInteractorIsReusedForSameSubId() =
+ testScope.runTest {
+ val interactor1 = underTest.mobileIconInteractorForSub(1)
+ val interactor2 = underTest.mobileIconInteractorForSub(1)
+
+ assertThat(interactor1).isSameInstanceAs(interactor2)
+ }
+
+ @Test
+ fun caching_invalidInteractorssAreRemovedFromCacheWhenSubDisappears() =
+ testScope.runTest {
+ // Retrieve interactors to trigger caching
+ val interactor1 = underTest.mobileIconInteractorForSub(1)
+ val interactor2 = underTest.mobileIconInteractorForSub(2)
+
+ // Both impls are cached
+ assertThat(underTest.mobileIconInteractorSubIdCache)
+ .containsExactly(1, interactor1, 2, interactor2)
+
+ // SUB_1 is removed from the list...
+ interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+ // ... and dropped from the cache
+ assertThat(underTest.mobileIconInteractorSubIdCache).containsExactly(2, interactor2)
+ }
+
+ @Test
fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
testScope.runTest {
var latest: Boolean? = null
@@ -308,8 +351,23 @@
}
companion object {
- private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
- private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
- private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false)
+ private val SUB_1 =
+ SubscriptionModel(
+ subscriptionId = 1,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ )
+ private val SUB_2 =
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = false,
+ carrierName = "Carrier 2",
+ )
+ private val SUB_3 =
+ SubscriptionModel(
+ subscriptionId = 3,
+ isOpportunistic = false,
+ carrierName = "Carrier 3",
+ )
}
}
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 ef39ff8..79feb41 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
@@ -82,7 +82,7 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -111,8 +111,8 @@
private BlockingQueueIntentReceiver mReceiver;
private final UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
- @ClassRule
- public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+ @Rule
+ public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
@Before
public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 0663004..69d7586 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -40,7 +40,6 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.CaptioningManager;
import androidx.test.filters.SmallTest;
@@ -64,6 +63,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Executor;
+
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper
@@ -96,8 +97,6 @@
@Mock
private WakefulnessLifecycle mWakefullnessLifcycle;
@Mock
- private CaptioningManager mCaptioningManager;
- @Mock
private KeyguardManager mKeyguardManager;
@Mock
private ActivityManager mActivityManager;
@@ -117,6 +116,7 @@
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
+ when(mUserTracker.getUserContext()).thenReturn(mContext);
// Enable group volume adjustments
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions,
@@ -127,7 +127,7 @@
mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
mNotificationManager, mVibrator, mIAudioService, mAccessibilityManager,
- mPackageManager, mWakefullnessLifcycle, mCaptioningManager, mKeyguardManager,
+ mPackageManager, mWakefullnessLifcycle, mKeyguardManager,
mActivityManager, mUserTracker, mDumpManager, mCallback);
mVolumeController.setEnableDialogs(true, true);
}
@@ -219,6 +219,11 @@
verify(mRingerModeInternalLiveData).observeForever(any());
}
+ @Test
+ public void testAddCallbackWithUserTracker() {
+ verify(mUserTracker).addCallback(any(UserTracker.Callback.class), any(Executor.class));
+ }
+
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
private final WakefulnessLifecycle.Observer mWakefullessLifecycleObserver;
@@ -234,7 +239,6 @@
AccessibilityManager accessibilityManager,
PackageManager packageManager,
WakefulnessLifecycle wakefulnessLifecycle,
- CaptioningManager captioningManager,
KeyguardManager keyguardManager,
ActivityManager activityManager,
UserTracker userTracker,
@@ -242,7 +246,7 @@
C callback) {
super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
notificationManager, optionalVibrator, iAudioService, accessibilityManager,
- packageManager, wakefulnessLifecycle, captioningManager, keyguardManager,
+ packageManager, wakefulnessLifecycle, keyguardManager,
activityManager, userTracker, dumpManager);
mCallbacks = callback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index fa18e57..a6a2761 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -31,14 +31,13 @@
import static org.junit.Assume.assumeNotNull;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.animation.AnimatorTestRule;
import android.app.KeyguardManager;
import android.content.res.Configuration;
import android.media.AudioManager;
@@ -85,14 +84,14 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class VolumeDialogImplTest extends SysuiTestCase {
- private static final AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule();
-
VolumeDialogImpl mDialog;
View mActiveRinger;
View mDrawerContainer;
View mDrawerVibrate;
View mDrawerMute;
View mDrawerNormal;
+ CaptionsToggleImageButton mODICaptionsIcon;
+
private TestableLooper mTestableLooper;
private ConfigurationController mConfigurationController;
private int mOriginalOrientation;
@@ -180,6 +179,7 @@
mDrawerVibrate = mDrawerContainer.findViewById(R.id.volume_drawer_vibrate);
mDrawerMute = mDrawerContainer.findViewById(R.id.volume_drawer_mute);
mDrawerNormal = mDrawerContainer.findViewById(R.id.volume_drawer_normal);
+ mODICaptionsIcon = mDialog.getDialogView().findViewById(R.id.odi_captions_icon);
Prefs.putInt(mContext,
Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT,
@@ -479,123 +479,45 @@
@Test
public void ifPortraitHalfOpen_drawVerticallyTop() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0 , null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_PORTRAIT);
// Call show() to trigger layout updates before verifying position
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
public void ifPortraitAndOpen_drawCenterVertically() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_PORTRAIT);
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
public void ifLandscapeAndHalfOpen_drawCenterVertically() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_LANDSCAPE);
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
@@ -606,31 +528,9 @@
@Test
public void dialogDestroy_removesPostureControllerCallback() {
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- mPostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
verify(mPostureController, never()).removeCallback(any());
- dialog.destroy();
-
+ mDialog.destroy();
verify(mPostureController).removeCallback(any());
-
- cleanUp(dialog);
}
private void setOrientation(int orientation) {
@@ -688,6 +588,28 @@
assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.CLOSE);
}
+ @Test
+ public void testOnCaptionEnabledStateChanged_checkBeforeSwitchTrue_setCaptionsEnabledState() {
+ ArgumentCaptor<VolumeDialogController.Callbacks> controllerCallbackCapture =
+ ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class);
+ verify(mVolumeDialogController).addCallback(controllerCallbackCapture.capture(), any());
+ VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue();
+
+ callbacks.onCaptionEnabledStateChanged(true, true);
+ verify(mVolumeDialogController).setCaptionsEnabledState(eq(false));
+ }
+
+ @Test
+ public void testOnCaptionEnabledStateChanged_checkBeforeSwitchFalse_getCaptionsEnabledTrue() {
+ ArgumentCaptor<VolumeDialogController.Callbacks> controllerCallbackCapture =
+ ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class);
+ verify(mVolumeDialogController).addCallback(controllerCallbackCapture.capture(), any());
+ VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue();
+
+ callbacks.onCaptionEnabledStateChanged(true, false);
+ assertTrue(mODICaptionsIcon.getCaptionsEnabled());
+ }
+
/**
* The content description should include ringer state, and the correct one.
*/
@@ -727,7 +649,6 @@
public void teardown() {
cleanUp(mDialog);
setOrientation(mOriginalOrientation);
- sAnimatorTestRule.advanceTimeBy(mLongestHideShowAnimationDuration);
mTestableLooper.moveTimeForward(mLongestHideShowAnimationDuration);
mTestableLooper.processAllMessages();
reset(mPostureController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
new file mode 100644
index 0000000..94ed608
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.wmshell
+
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.model.SysUiStateTest
+import com.android.wm.shell.bubbles.Bubble
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.PREF_MANAGED_EDUCATION
+import com.android.wm.shell.bubbles.PREF_STACK_EDUCATION
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class BubbleEducationControllerTest : SysUiStateTest() {
+ private val sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor::class.java)
+ private val sharedPrefs = Mockito.mock(SharedPreferences::class.java)
+ private val context = Mockito.mock(Context::class.java)
+ private lateinit var sut: BubbleEducationController
+
+ @Before
+ fun setUp() {
+ Mockito.`when`(context.packageName).thenReturn("packageName")
+ Mockito.`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs)
+ Mockito.`when`(context.contentResolver)
+ .thenReturn(Mockito.mock(ContentResolver::class.java))
+ Mockito.`when`(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
+ sut = BubbleEducationController(context)
+ }
+
+ @Test
+ fun testSeenStackEducation_read() {
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.hasSeenStackEducation, true)
+ Mockito.verify(sharedPrefs).getBoolean(PREF_STACK_EDUCATION, false)
+ }
+
+ @Test
+ fun testSeenStackEducation_write() {
+ sut.hasSeenStackEducation = true
+ Mockito.verify(sharedPrefsEditor).putBoolean(PREF_STACK_EDUCATION, true)
+ }
+
+ @Test
+ fun testSeenManageEducation_read() {
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.hasSeenManageEducation, true)
+ Mockito.verify(sharedPrefs).getBoolean(PREF_MANAGED_EDUCATION, false)
+ }
+
+ @Test
+ fun testSeenManageEducation_write() {
+ sut.hasSeenManageEducation = true
+ Mockito.verify(sharedPrefsEditor).putBoolean(PREF_MANAGED_EDUCATION, true)
+ }
+
+ @Test
+ fun testShouldShowStackEducation() {
+ val bubble = Mockito.mock(Bubble::class.java)
+ // When bubble is null
+ assertEquals(sut.shouldShowStackEducation(null), false)
+ // When bubble is not conversation
+ Mockito.`when`(bubble.isConversation).thenReturn(false)
+ assertEquals(sut.shouldShowStackEducation(bubble), false)
+ // When bubble is conversation and has seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.shouldShowStackEducation(bubble), false)
+ // When bubble is conversation and has not seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ assertEquals(sut.shouldShowStackEducation(bubble), true)
+ }
+
+ @Test
+ fun testShouldShowManageEducation() {
+ val bubble = Mockito.mock(Bubble::class.java)
+ // When bubble is null
+ assertEquals(sut.shouldShowManageEducation(null), false)
+ // When bubble is not conversation
+ Mockito.`when`(bubble.isConversation).thenReturn(false)
+ assertEquals(sut.shouldShowManageEducation(bubble), false)
+ // When bubble is conversation and has seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.shouldShowManageEducation(bubble), false)
+ // When bubble is conversation and has not seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ assertEquals(sut.shouldShowManageEducation(bubble), true)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
index 19c68e8..41dbc14 100644
--- a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
+++ b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
@@ -49,7 +49,7 @@
* public class SampleAnimatorTest {
*
* {@literal @}Rule
- * public AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule();
+ * public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
*
* {@literal @}UiThreadTest
* {@literal @}Test
@@ -58,7 +58,7 @@
* animator.setDuration(1000L);
* assertThat(animator.getAnimatedValue(), is(0));
* animator.start();
- * sAnimatorTestRule.advanceTimeBy(500L);
+ * mAnimatorTestRule.advanceTimeBy(500L);
* assertThat(animator.getAnimatedValue(), is(500));
* }
* }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
index 8c98aea..e91e955 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
@@ -22,32 +22,24 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
class FakeBiometricSettingsRepository : BiometricSettingsRepository {
+ private val _isFingerprintEnrolledAndEnabled = MutableStateFlow(false)
+ override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
+ get() = _isFingerprintEnrolledAndEnabled
- private val _isFingerprintEnrolled = MutableStateFlow<Boolean>(false)
- override val isFingerprintEnrolled: StateFlow<Boolean> = _isFingerprintEnrolled.asStateFlow()
+ private val _isFingerprintAuthCurrentlyAllowed = MutableStateFlow(false)
+ override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean>
+ get() = _isFingerprintAuthCurrentlyAllowed
- private val _isFaceEnrolled = MutableStateFlow(false)
- override val isFaceEnrolled: Flow<Boolean>
- get() = _isFaceEnrolled
+ private val _isFaceAuthEnrolledAndEnabled = MutableStateFlow(false)
+ override val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
+ get() = _isFaceAuthEnrolledAndEnabled
- private val _isFaceAuthEnabled = MutableStateFlow(false)
- override val isFaceAuthenticationEnabled: Flow<Boolean>
- get() = _isFaceAuthEnabled
-
- private val _isStrongBiometricAllowed = MutableStateFlow(false)
- override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow()
-
- private val _isNonStrongBiometricAllowed = MutableStateFlow(false)
- override val isNonStrongBiometricAllowed: StateFlow<Boolean>
- get() = _isNonStrongBiometricAllowed
-
- private val _isFingerprintEnabledByDevicePolicy = MutableStateFlow(false)
- override val isFingerprintEnabledByDevicePolicy =
- _isFingerprintEnabledByDevicePolicy.asStateFlow()
+ private val _isFaceAuthCurrentlyAllowed = MutableStateFlow(false)
+ override val isFaceAuthCurrentlyAllowed: Flow<Boolean>
+ get() = _isFaceAuthCurrentlyAllowed
private val _isFaceAuthSupportedInCurrentPosture = MutableStateFlow(false)
override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
@@ -59,34 +51,33 @@
private val _authFlags = MutableStateFlow(AuthenticationFlags(0, 0))
override val authenticationFlags: Flow<AuthenticationFlags>
get() = _authFlags
- fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) {
- _isFingerprintEnrolled.value = isFingerprintEnrolled
- }
-
- fun setStrongBiometricAllowed(isStrongBiometricAllowed: Boolean) {
- _isStrongBiometricAllowed.value = isStrongBiometricAllowed
- }
-
- fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) {
- _isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy
- }
fun setAuthenticationFlags(value: AuthenticationFlags) {
_authFlags.value = value
}
- fun setFaceEnrolled(isFaceEnrolled: Boolean) {
- _isFaceEnrolled.value = isFaceEnrolled
+ fun setIsFingerprintAuthEnrolledAndEnabled(value: Boolean) {
+ _isFingerprintEnrolledAndEnabled.value = value
+ _isFingerprintAuthCurrentlyAllowed.value = _isFingerprintAuthCurrentlyAllowed.value && value
+ }
+
+ fun setIsFingerprintAuthCurrentlyAllowed(value: Boolean) {
+ _isFingerprintAuthCurrentlyAllowed.value = value
+ }
+
+ fun setIsFaceAuthEnrolledAndEnabled(value: Boolean) {
+ _isFaceAuthEnrolledAndEnabled.value = value
+ _isFaceAuthCurrentlyAllowed.value = _isFaceAuthCurrentlyAllowed.value && value
+ }
+
+ fun setIsFaceAuthCurrentlyAllowed(value: Boolean) {
+ _isFaceAuthCurrentlyAllowed.value = value
}
fun setIsFaceAuthSupportedInCurrentPosture(value: Boolean) {
_isFaceAuthSupportedInCurrentPosture.value = value
}
- fun setIsFaceAuthEnabled(enabled: Boolean) {
- _isFaceAuthEnabled.value = enabled
- }
-
fun setIsUserInLockdown(value: Boolean) {
if (value) {
setAuthenticationFlags(
@@ -105,12 +96,4 @@
)
}
}
-
- fun setIsNonStrongBiometricAllowed(value: Boolean) {
- _isNonStrongBiometricAllowed.value = value
- }
-
- fun setIsStrongBiometricAllowed(value: Boolean) {
- _isStrongBiometricAllowed.value = value
- }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index dd45331..f0e1111 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -39,8 +39,6 @@
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.RemoteUserInput
-import com.android.systemui.scene.shared.model.RemoteUserInputAction
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -196,15 +194,6 @@
}
companion object {
- val REMOTE_INPUT_DOWN_GESTURE =
- listOf(
- RemoteUserInput(10f, 10f, RemoteUserInputAction.DOWN),
- RemoteUserInput(10f, 20f, RemoteUserInputAction.MOVE),
- RemoteUserInput(10f, 30f, RemoteUserInputAction.MOVE),
- RemoteUserInput(10f, 40f, RemoteUserInputAction.MOVE),
- RemoteUserInput(10f, 40f, RemoteUserInputAction.UP),
- )
-
fun DomainLayerAuthenticationMethodModel.toDataLayer(): DataLayerAuthenticationMethodModel {
return when (this) {
DomainLayerAuthenticationMethodModel.None -> DataLayerAuthenticationMethodModel.None
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 315972c..f594170 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -1225,15 +1225,13 @@
public ContentCaptureOptions getOptions(@UserIdInt int userId,
@NonNull String packageName) {
boolean isContentCaptureReceiverEnabled;
- boolean isContentProtectionReceiverEnabled;
+ boolean isContentProtectionReceiverEnabled =
+ isContentProtectionReceiverEnabled(userId, packageName);
ArraySet<ComponentName> whitelistedComponents = null;
synchronized (mGlobalWhitelistStateLock) {
isContentCaptureReceiverEnabled =
isContentCaptureReceiverEnabled(userId, packageName);
- isContentProtectionReceiverEnabled =
- isContentProtectionReceiverEnabled(userId, packageName);
-
if (!isContentCaptureReceiverEnabled) {
// Full package is not allowlisted: check individual components next
whitelistedComponents = getWhitelistedComponents(userId, packageName);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index b67e627..d47a399 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -81,7 +81,7 @@
# when a notification has been clicked
27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
# when a notification action button has been clicked
-27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
+27521 notification_action_clicked (key|3),(piIdentifier|3),(pendingIntent|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
# when a notification has been canceled
27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1),(listener|3)
# replaces 27510 with a row per notification
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 9f9e2eb..b5cab17 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -391,7 +391,6 @@
final boolean wasBtScoRequested = isBluetoothScoRequested();
CommunicationRouteClient client;
-
// Save previous client route in case of failure to start BT SCO audio
AudioDeviceAttributes prevClientDevice = null;
boolean prevPrivileged = false;
@@ -1043,7 +1042,7 @@
synchronized (mBluetoothAudioStateLock) {
mBluetoothScoOn = on;
updateAudioHalBluetoothState();
- postUpdateCommunicationRouteClient(eventSource);
+ postUpdateCommunicationRouteClient(isBluetoothScoRequested(), eventSource);
}
}
@@ -1395,8 +1394,10 @@
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
}
- /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
- sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
+ /*package*/ void postUpdateCommunicationRouteClient(
+ boolean wasBtScoRequested, String eventSource) {
+ sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
+ wasBtScoRequested ? 1 : 0, eventSource);
}
/*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
@@ -1708,7 +1709,8 @@
: AudioSystem.STREAM_DEFAULT);
if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile == BluetoothProfile.HEARING_AID) {
- onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
+ onUpdateCommunicationRouteClient(isBluetoothScoRequested(),
+ "setBluetoothActiveDevice");
}
}
}
@@ -1762,9 +1764,11 @@
case MSG_I_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ boolean wasBtScoRequested = isBluetoothScoRequested();
mAudioModeOwner = (AudioModeInfo) msg.obj;
if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
- onUpdateCommunicationRouteClient("setNewModeOwner");
+ onUpdateCommunicationRouteClient(
+ wasBtScoRequested, "setNewModeOwner");
}
}
}
@@ -1787,10 +1791,10 @@
}
break;
- case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+ case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- onUpdateCommunicationRouteClient((String) msg.obj);
+ onUpdateCommunicationRouteClient(msg.arg1 == 1, (String) msg.obj);
}
}
break;
@@ -1973,7 +1977,7 @@
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
- private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+ private static final int MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
@@ -2330,16 +2334,20 @@
*/
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
- private void onUpdateCommunicationRouteClient(String eventSource) {
- updateCommunicationRoute(eventSource);
+ private void onUpdateCommunicationRouteClient(boolean wasBtScoRequested, String eventSource) {
CommunicationRouteClient crc = topCommunicationRouteClient();
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
- + crc + " eventSource: " + eventSource);
+ Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
+ + " wasBtScoRequested: " + wasBtScoRequested + " eventSource: " + eventSource);
}
if (crc != null) {
setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
+ } else {
+ if (!isBluetoothScoRequested() && wasBtScoRequested) {
+ mBtHelper.stopBluetoothSco(eventSource);
+ }
+ updateCommunicationRoute(eventSource);
}
}
@@ -2403,7 +2411,11 @@
}
@GuardedBy("mDeviceStateLock")
- private boolean communnicationDeviceCompatOn() {
+ // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio
+ // policy routing rules select the default communication device.
+ // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE
+ // Audiodevice explicitly.
+ private boolean communnicationDeviceLeAudioCompatOn() {
return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
&& !(CompatChanges.isChangeEnabled(
USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
@@ -2411,19 +2423,25 @@
}
@GuardedBy("mDeviceStateLock")
+ // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio
+ // policy routing rules select the default communication device.
+ // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain
+ // backwards compatibility
+ private boolean communnicationDeviceHaCompatOn() {
+ return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
+ }
+
+ @GuardedBy("mDeviceStateLock")
AudioDeviceAttributes getDefaultCommunicationDevice() {
- // For system server (Telecom) and APKs targeting S and above, we let the audio
- // policy routing rules select the default communication device.
- // For older APKs, we force Hearing Aid or LE Audio headset when connected as
- // those APKs cannot select a LE Audio or Hearing Aid device explicitly.
AudioDeviceAttributes device = null;
- if (communnicationDeviceCompatOn()) {
- // If both LE and Hearing Aid are active (thie should not happen),
- // priority to Hearing Aid.
+ // If both LE and Hearing Aid are active (thie should not happen),
+ // priority to Hearing Aid.
+ if (communnicationDeviceHaCompatOn()) {
device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
- if (device == null) {
- device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
- }
+ }
+ if (device == null && communnicationDeviceLeAudioCompatOn()) {
+ device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
}
return device;
}
@@ -2433,6 +2451,7 @@
List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ final boolean wasBtScoRequested = isBluetoothScoRequested();
boolean updateCommunicationRoute = false;
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
boolean wasActive = crc.isActive();
@@ -2461,7 +2480,8 @@
}
}
if (updateCommunicationRoute) {
- postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity");
+ postUpdateCommunicationRouteClient(
+ wasBtScoRequested, "updateCommunicationRouteClientsActivity");
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6a73c2b..ceb96ef 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -10691,6 +10691,27 @@
@Override
@android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public boolean isCsdAsAFeatureAvailable() {
+ super.isCsdAsAFeatureAvailable_enforcePermission();
+ return mSoundDoseHelper.isCsdAsAFeatureAvailable();
+ }
+
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public boolean isCsdAsAFeatureEnabled() {
+ super.isCsdAsAFeatureEnabled_enforcePermission();
+ return mSoundDoseHelper.isCsdAsAFeatureEnabled();
+ }
+
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setCsdAsAFeatureEnabled(boolean csdToggleValue) {
+ super.setCsdAsAFeatureEnabled_enforcePermission();
+ mSoundDoseHelper.setCsdAsAFeatureEnabled(csdToggleValue);
+ }
+
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
public void setBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle,
@AudioDeviceCategory int btAudioDeviceCategory) {
super.setBluetoothAudioDeviceCategory_enforcePermission();
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 3560797..a4d26d3 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -329,7 +329,7 @@
default:
break;
}
- if(broadcast) {
+ if (broadcast) {
broadcastScoConnectionState(scoAudioState);
//FIXME: this is to maintain compatibility with deprecated intent
// AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
@@ -718,8 +718,10 @@
checkScoAudioState();
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
// Make sure that the state transitions to CONNECTING even if we cannot initiate
- // the connection.
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+ // the connection except if already connected internally
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL) {
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+ }
switch (mScoAudioState) {
case SCO_STATE_INACTIVE:
mScoAudioMode = scoAudioMode;
@@ -775,7 +777,7 @@
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
break;
case SCO_STATE_ACTIVE_INTERNAL:
- Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
+ // Already in ACTIVE mode, simply return
break;
case SCO_STATE_ACTIVE_EXTERNAL:
/* Confirm SCO Audio connection to requesting app as it is already connected
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 851c5c3..5ebc1c0 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -37,13 +37,11 @@
import android.media.ISoundDoseCallback;
import android.media.SoundDoseRecord;
import android.os.Binder;
-import android.os.HandlerExecutor;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -143,8 +141,6 @@
private static final int SAFE_MEDIA_VOLUME_UNINITIALIZED = -1;
- private static final String FEATURE_FLAG_ENABLE_CSD = "enable_csd";
-
private final EventLogger mLogger = new EventLogger(AudioService.LOG_NB_EVENTS_SOUND_DOSE,
"CSD updates");
@@ -193,7 +189,15 @@
private final AtomicBoolean mEnableCsd = new AtomicBoolean(false);
- private ArrayList<ISoundDose.AudioDeviceCategory> mCachedAudioDeviceCategories =
+ private final Object mCsdAsAFeatureLock = new Object();
+
+ @GuardedBy("mCsdAsAFeatureLock")
+ private boolean mIsCsdAsAFeatureAvailable = false;
+
+ @GuardedBy("mCsdAsAFeatureLock")
+ private boolean mIsCsdAsAFeatureEnabled = false;
+
+ private final ArrayList<ISoundDose.AudioDeviceCategory> mCachedAudioDeviceCategories =
new ArrayList<>();
private final Object mCsdStateLock = new Object();
@@ -315,10 +319,6 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
-
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_MEDIA,
- new HandlerExecutor(mAudioHandler),
- p -> updateCsdEnabled("onPropertiesChanged"));
}
void initSafeVolumes() {
@@ -494,6 +494,38 @@
return false;
}
+ boolean isCsdAsAFeatureAvailable() {
+ synchronized (mCsdAsAFeatureLock) {
+ return mIsCsdAsAFeatureAvailable;
+ }
+ }
+
+ boolean isCsdAsAFeatureEnabled() {
+ synchronized (mCsdAsAFeatureLock) {
+ return mIsCsdAsAFeatureEnabled;
+ }
+ }
+
+ void setCsdAsAFeatureEnabled(boolean csdAsAFeatureEnabled) {
+ boolean doUpdate;
+ synchronized (mCsdAsAFeatureLock) {
+ doUpdate = mIsCsdAsAFeatureEnabled != csdAsAFeatureEnabled && mIsCsdAsAFeatureAvailable;
+ mIsCsdAsAFeatureEnabled = csdAsAFeatureEnabled;
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mSettings.putSecureIntForUser(mAudioService.getContentResolver(),
+ Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED,
+ mIsCsdAsAFeatureEnabled ? 1 : 0, UserHandle.USER_CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ if (doUpdate) {
+ updateCsdEnabled("setCsdAsAFeatureEnabled");
+ }
+ }
+
void setAudioDeviceCategory(String address, int internalAudioType, boolean isHeadphone) {
if (!mEnableCsd.get()) {
return;
@@ -864,6 +896,13 @@
Log.e(TAG, "Exception while forcing the internal MEL computation", e);
}
+ synchronized (mCsdAsAFeatureLock) {
+ mIsCsdAsAFeatureEnabled = mSettings.getSecureIntForUser(
+ mAudioService.getContentResolver(),
+ Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED, 0,
+ UserHandle.USER_CURRENT) != 0;
+ }
+
synchronized (mCsdStateLock) {
if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
@@ -908,18 +947,23 @@
@GuardedBy("mSafeMediaVolumeStateLock")
private void updateSafeMediaVolume_l(String caller) {
- boolean safeMediaVolumeEnabled =
- SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE, false)
- || (mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_safe_media_volume_enabled)
- && !mEnableCsd.get());
boolean safeMediaVolumeBypass =
- SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false);
+ SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false)
+ || mEnableCsd.get();
+ boolean safeMediaVolumeForce = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE,
+ false);
+ // we are using the MCC overlaid legacy flag used for the safe volume enablement
+ // to determine whether the MCC enforces any safe hearing standard.
+ boolean mccEnforcedSafeMediaVolume = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_safe_media_volume_enabled);
+
+ boolean safeVolumeEnabled =
+ (mccEnforcedSafeMediaVolume || safeMediaVolumeForce) && !safeMediaVolumeBypass;
// The persisted state is either "disabled" or "active": this is the state applied
// next time we boot and cannot be "inactive"
int persistedState;
- if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
+ if (safeVolumeEnabled) {
persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
// The state can already be "inactive" here if the user has forced it before
// the 30 seconds timeout for forced configuration. In this case we don't reset
@@ -946,22 +990,28 @@
}
private void updateCsdEnabled(String caller) {
- boolean newEnableCsd = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE,
- false);
- if (!newEnableCsd) {
- final String featureFlagEnableCsdValue = DeviceConfig.getProperty(
- DeviceConfig.NAMESPACE_MEDIA,
- FEATURE_FLAG_ENABLE_CSD);
- if (featureFlagEnableCsdValue != null) {
- newEnableCsd = Boolean.parseBoolean(featureFlagEnableCsdValue);
+ boolean csdForce = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE, false);
+ // we are using the MCC overlaid legacy flag used for the safe volume enablement
+ // to determine whether the MCC enforces any safe hearing standard.
+ boolean mccEnforcedSafeMedia = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_safe_media_volume_enabled);
+ boolean csdEnable = mContext.getResources().getBoolean(
+ R.bool.config_safe_sound_dosage_enabled);
+ boolean newEnabledCsd = (mccEnforcedSafeMedia && csdEnable) || csdForce;
+
+ synchronized (mCsdAsAFeatureLock) {
+ if (!mccEnforcedSafeMedia && csdEnable) {
+ mIsCsdAsAFeatureAvailable = true;
+ newEnabledCsd = mIsCsdAsAFeatureEnabled || csdForce;
+ Log.v(TAG, caller + ": CSD as a feature is not enforced and enabled: "
+ + newEnabledCsd);
} else {
- newEnableCsd = mContext.getResources().getBoolean(
- R.bool.config_safe_sound_dosage_enabled);
+ mIsCsdAsAFeatureAvailable = false;
}
}
- if (mEnableCsd.compareAndSet(!newEnableCsd, newEnableCsd)) {
- Log.i(TAG, caller + ": enable CSD " + newEnableCsd);
+ if (mEnableCsd.compareAndSet(!newEnabledCsd, newEnabledCsd)) {
+ Log.i(TAG, caller + ": enabled CSD " + newEnabledCsd);
initCsd();
synchronized (mSafeMediaVolumeStateLock) {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStats.java b/services/core/java/com/android/server/biometrics/AuthenticationStats.java
index 137a418..e109cc8 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStats.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStats.java
@@ -22,6 +22,8 @@
*/
public class AuthenticationStats {
+ private static final float FRR_NOT_ENOUGH_ATTEMPTS = -1.0f;
+
private final int mUserId;
private int mTotalAttempts;
private int mRejectedAttempts;
@@ -70,7 +72,7 @@
if (mTotalAttempts > 0) {
return mRejectedAttempts / (float) mTotalAttempts;
} else {
- return -1.0f;
+ return FRR_NOT_ENOUGH_ATTEMPTS;
}
}
@@ -87,4 +89,32 @@
mTotalAttempts = 0;
mRejectedAttempts = 0;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof AuthenticationStats)) {
+ return false;
+ }
+
+ AuthenticationStats target = (AuthenticationStats) obj;
+ return this.getUserId() == target.getUserId()
+ && this.getTotalAttempts()
+ == target.getTotalAttempts()
+ && this.getRejectedAttempts()
+ == target.getRejectedAttempts()
+ && this.getEnrollmentNotifications()
+ == target.getEnrollmentNotifications()
+ && this.getModality() == target.getModality();
+ }
+
+ @Override
+ public int hashCode() {
+ return String.format("userId: %d, totalAttempts: %d, rejectedAttempts: %d, "
+ + "enrollmentNotifications: %d, modality: %d", mUserId, mTotalAttempts,
+ mRejectedAttempts, mEnrollmentNotifications, mModality).hashCode();
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index c9cd814..97e5c6f 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -18,10 +18,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.sensors.BiometricNotification;
import java.util.HashMap;
import java.util.Map;
@@ -37,23 +45,60 @@
// The minimum number of attempts that will calculate the FRR and trigger the notification.
private static final int MINIMUM_ATTEMPTS = 500;
+ // Upload the data every 50 attempts (average number of daily authentications).
+ private static final int AUTHENTICATION_UPLOAD_INTERVAL = 50;
// The maximum number of eligible biometric enrollment notification can be sent.
private static final int MAXIMUM_ENROLLMENT_NOTIFICATIONS = 2;
+ @NonNull private final Context mContext;
+
private final float mThreshold;
private final int mModality;
@NonNull private final Map<Integer, AuthenticationStats> mUserAuthenticationStatsMap;
- public AuthenticationStatsCollector(@NonNull Context context, int modality) {
+ // TODO(b/295582896): Find a way to make this NonNull
+ @Nullable private AuthenticationStatsPersister mAuthenticationStatsPersister;
+ @NonNull private BiometricNotification mBiometricNotification;
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId != UserHandle.USER_NULL
+ && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
+ onUserRemoved(userId);
+ }
+ }
+ };
+
+ public AuthenticationStatsCollector(@NonNull Context context, int modality,
+ @NonNull BiometricNotification biometricNotification) {
+ mContext = context;
mThreshold = context.getResources()
.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1);
mUserAuthenticationStatsMap = new HashMap<>();
mModality = modality;
+ mBiometricNotification = biometricNotification;
+
+ context.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+ }
+
+ private void initializeUserAuthenticationStatsMap() {
+ mAuthenticationStatsPersister = new AuthenticationStatsPersister(mContext);
+ for (AuthenticationStats stats : mAuthenticationStatsPersister.getAllFrrStats(mModality)) {
+ mUserAuthenticationStatsMap.put(stats.getUserId(), stats);
+ }
}
/** Update total authentication and rejected attempts. */
public void authenticate(int userId, boolean authenticated) {
+ // SharedPreference is not ready when starting system server, initialize
+ // mUserAuthenticationStatsMap in authentication to ensure SharedPreference
+ // is ready for application use.
+ if (mUserAuthenticationStatsMap.isEmpty()) {
+ initializeUserAuthenticationStatsMap();
+ }
// Check if this is a new user.
if (!mUserAuthenticationStatsMap.containsKey(userId)) {
mUserAuthenticationStatsMap.put(userId, new AuthenticationStats(userId, mModality));
@@ -67,26 +112,67 @@
sendNotificationIfNeeded(userId);
}
+ /** Check if a notification should be sent after a calculation cycle. */
private void sendNotificationIfNeeded(int userId) {
AuthenticationStats authenticationStats = mUserAuthenticationStatsMap.get(userId);
- if (authenticationStats.getTotalAttempts() >= MINIMUM_ATTEMPTS) {
- // Send notification if FRR exceeds the threshold
- if (authenticationStats.getEnrollmentNotifications() < MAXIMUM_ENROLLMENT_NOTIFICATIONS
- && authenticationStats.getFrr() >= mThreshold) {
- // TODO(wenhuiy): Send notifications.
- }
+ if (authenticationStats.getTotalAttempts() < MINIMUM_ATTEMPTS) {
+ return;
+ }
+ // Don't send notification if FRR below the threshold.
+ if (authenticationStats.getEnrollmentNotifications() >= MAXIMUM_ENROLLMENT_NOTIFICATIONS
+ || authenticationStats.getFrr() < mThreshold) {
authenticationStats.resetData();
+ return;
+ }
+
+ authenticationStats.resetData();
+
+ final PackageManager packageManager = mContext.getPackageManager();
+
+ // Don't send notification to single-modality devices.
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+ || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ return;
+ }
+
+ final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
+ final boolean hasEnrolledFace = faceManager.hasEnrolledTemplates(userId);
+
+ final FingerprintManager fingerprintManager = mContext
+ .getSystemService(FingerprintManager.class);
+ final boolean hasEnrolledFingerprint = fingerprintManager.hasEnrolledTemplates(userId);
+
+ // Don't send notification when both face and fingerprint are enrolled.
+ if (hasEnrolledFace && hasEnrolledFingerprint) {
+ return;
+ }
+ if (hasEnrolledFace && !hasEnrolledFingerprint) {
+ mBiometricNotification.sendFpEnrollNotification(mContext);
+ } else if (!hasEnrolledFace && hasEnrolledFingerprint) {
+ mBiometricNotification.sendFaceEnrollNotification(mContext);
}
}
private void persistDataIfNeeded(int userId) {
AuthenticationStats authenticationStats = mUserAuthenticationStatsMap.get(userId);
- if (authenticationStats.getTotalAttempts() % 50 == 0) {
- // TODO(wenhuiy): Persist data.
+ if (authenticationStats.getTotalAttempts() % AUTHENTICATION_UPLOAD_INTERVAL == 0) {
+ mAuthenticationStatsPersister.persistFrrStats(authenticationStats.getUserId(),
+ authenticationStats.getTotalAttempts(),
+ authenticationStats.getRejectedAttempts(),
+ authenticationStats.getEnrollmentNotifications(),
+ authenticationStats.getModality());
}
}
+ private void onUserRemoved(final int userId) {
+ if (mAuthenticationStatsPersister == null) {
+ initializeUserAuthenticationStatsMap();
+ }
+ mUserAuthenticationStatsMap.remove(userId);
+ mAuthenticationStatsPersister.removeFrrStats(userId);
+ }
+
/**
* Only being used in tests. Callers should not make any changes to the returned
* authentication stats.
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java
new file mode 100644
index 0000000..21e93a8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java
@@ -0,0 +1,215 @@
+/*
+ * 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.biometrics;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.Environment;
+import android.util.Slog;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Persists and retrieves stats for Biometric Authentication.
+ * Authentication stats include userId, total attempts, rejected attempts,
+ * and the number of sent enrollment notifications.
+ * Data are stored in SharedPreferences in a form of a set of JSON objects,
+ * where it's one element per user.
+ */
+public class AuthenticationStatsPersister {
+
+ private static final String TAG = "AuthenticationStatsPersister";
+ private static final String FILE_NAME = "authentication_stats";
+ private static final String USER_ID = "user_id";
+ private static final String FACE_ATTEMPTS = "face_attempts";
+ private static final String FACE_REJECTIONS = "face_rejections";
+ private static final String FINGERPRINT_ATTEMPTS = "fingerprint_attempts";
+ private static final String FINGERPRINT_REJECTIONS = "fingerprint_rejections";
+ private static final String ENROLLMENT_NOTIFICATIONS = "enrollment_notifications";
+ private static final String KEY = "frr_stats";
+
+ @NonNull private final SharedPreferences mSharedPreferences;
+
+ AuthenticationStatsPersister(@NonNull Context context) {
+ // The package info in the context isn't initialized in the way it is for normal apps,
+ // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
+ // build the path manually below using the same policy that appears in ContextImpl.
+ final File prefsFile = new File(Environment.getDataSystemDeDirectory(), FILE_NAME);
+ mSharedPreferences = context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Get all frr data from SharedPreference.
+ */
+ public List<AuthenticationStats> getAllFrrStats(int modality) {
+ List<AuthenticationStats> authenticationStatsList = new ArrayList<>();
+ for (String frrStats : readFrrStats()) {
+ try {
+ JSONObject frrStatsJson = new JSONObject(frrStats);
+ if (modality == BiometricsProtoEnums.MODALITY_FACE) {
+ authenticationStatsList.add(new AuthenticationStats(
+ getIntValue(frrStatsJson, USER_ID, -1 /* defaultValue */),
+ getIntValue(frrStatsJson, FACE_ATTEMPTS),
+ getIntValue(frrStatsJson, FACE_REJECTIONS),
+ getIntValue(frrStatsJson, ENROLLMENT_NOTIFICATIONS),
+ modality));
+ } else if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+ authenticationStatsList.add(new AuthenticationStats(
+ getIntValue(frrStatsJson, USER_ID, -1 /* defaultValue */),
+ getIntValue(frrStatsJson, FINGERPRINT_ATTEMPTS),
+ getIntValue(frrStatsJson, FINGERPRINT_REJECTIONS),
+ getIntValue(frrStatsJson, ENROLLMENT_NOTIFICATIONS),
+ modality));
+ }
+ } catch (JSONException e) {
+ Slog.w(TAG, String.format("Unable to resolve authentication stats JSON: %s",
+ frrStats));
+ }
+ }
+ return authenticationStatsList;
+ }
+
+ /**
+ * Remove frr data for a specific user.
+ */
+ public void removeFrrStats(int userId) {
+ try {
+ // Copy into a new HashSet to allow modification.
+ Set<String> frrStatsSet = new HashSet<>(readFrrStats());
+
+ // Remove the old authentication stat for the user if it exists.
+ for (Iterator<String> iterator = frrStatsSet.iterator(); iterator.hasNext();) {
+ String frrStats = iterator.next();
+ JSONObject frrStatJson = new JSONObject(frrStats);
+ if (getValue(frrStatJson, USER_ID).equals(String.valueOf(userId))) {
+ iterator.remove();
+ break;
+ }
+ }
+
+ mSharedPreferences.edit().putStringSet(KEY, frrStatsSet).apply();
+ } catch (JSONException ignored) {
+ }
+ }
+
+ /**
+ * Persist frr data for a specific user.
+ */
+ public void persistFrrStats(int userId, int totalAttempts, int rejectedAttempts,
+ int enrollmentNotifications, int modality) {
+ try {
+ // Copy into a new HashSet to allow modification.
+ Set<String> frrStatsSet = new HashSet<>(readFrrStats());
+
+ // Remove the old authentication stat for the user if it exists.
+ JSONObject frrStatJson = null;
+ for (Iterator<String> iterator = frrStatsSet.iterator(); iterator.hasNext();) {
+ String frrStats = iterator.next();
+ frrStatJson = new JSONObject(frrStats);
+ if (getValue(frrStatJson, USER_ID).equals(String.valueOf(userId))) {
+ iterator.remove();
+ break;
+ }
+ }
+
+ // If there's existing frr stats in the file, we want to update the stats for the given
+ // modality and keep the stats for other modalities.
+ if (frrStatJson != null) {
+ frrStatsSet.add(buildFrrStats(frrStatJson, totalAttempts, rejectedAttempts,
+ enrollmentNotifications, modality));
+ } else {
+ frrStatsSet.add(buildFrrStats(userId, totalAttempts, rejectedAttempts,
+ enrollmentNotifications, modality));
+ }
+
+ mSharedPreferences.edit().putStringSet(KEY, frrStatsSet).apply();
+
+ } catch (JSONException e) {
+ Slog.e(TAG, "Unable to persist authentication stats");
+ }
+ }
+
+ private Set<String> readFrrStats() {
+ return mSharedPreferences.getStringSet(KEY, Set.of());
+ }
+
+ // Update frr stats for existing frrStats JSONObject and build the new string.
+ private String buildFrrStats(JSONObject frrStats, int totalAttempts, int rejectedAttempts,
+ int enrollmentNotifications, int modality) throws JSONException {
+ if (modality == BiometricsProtoEnums.MODALITY_FACE) {
+ return frrStats
+ .put(FACE_ATTEMPTS, totalAttempts)
+ .put(FACE_REJECTIONS, rejectedAttempts)
+ .put(ENROLLMENT_NOTIFICATIONS, enrollmentNotifications)
+ .toString();
+ } else if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+ return frrStats
+ .put(FINGERPRINT_ATTEMPTS, totalAttempts)
+ .put(FINGERPRINT_REJECTIONS, rejectedAttempts)
+ .put(ENROLLMENT_NOTIFICATIONS, enrollmentNotifications)
+ .toString();
+ } else {
+ return frrStats.toString();
+ }
+ }
+
+ // Build string for new user and new authentication stats.
+ private String buildFrrStats(int userId, int totalAttempts, int rejectedAttempts,
+ int enrollmentNotifications, int modality)
+ throws JSONException {
+ if (modality == BiometricsProtoEnums.MODALITY_FACE) {
+ return new JSONObject()
+ .put(USER_ID, userId)
+ .put(FACE_ATTEMPTS, totalAttempts)
+ .put(FACE_REJECTIONS, rejectedAttempts)
+ .put(ENROLLMENT_NOTIFICATIONS, enrollmentNotifications)
+ .toString();
+ } else if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+ return new JSONObject()
+ .put(USER_ID, userId)
+ .put(FINGERPRINT_ATTEMPTS, totalAttempts)
+ .put(FINGERPRINT_REJECTIONS, rejectedAttempts)
+ .put(ENROLLMENT_NOTIFICATIONS, enrollmentNotifications)
+ .toString();
+ } else {
+ return "";
+ }
+ }
+
+ private String getValue(JSONObject jsonObject, String key) throws JSONException {
+ return jsonObject.has(key) ? jsonObject.getString(key) : "";
+ }
+
+ private int getIntValue(JSONObject jsonObject, String key) throws JSONException {
+ return getIntValue(jsonObject, key, 0 /* defaultValue */);
+ }
+
+ private int getIntValue(JSONObject jsonObject, String key, int defaultValue)
+ throws JSONException {
+ return jsonObject.has(key) ? jsonObject.getInt(key) : defaultValue;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotification.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotification.java
new file mode 100644
index 0000000..90e1860
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotification.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * Interface for biometrics to send notifications.
+ */
+public interface BiometricNotification {
+
+ /**
+ * Sends a face enrollment notification.
+ */
+ void sendFaceEnrollNotification(@NonNull Context context);
+
+ /**
+ * Sends a fingerprint enrollment notification.
+ */
+ void sendFpEnrollNotification(@NonNull Context context);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationImpl.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationImpl.java
new file mode 100644
index 0000000..7b42046
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.server.biometrics.AuthenticationStatsCollector;
+
+/**
+ * Implementation to send biometric notifications for {@link AuthenticationStatsCollector}.
+ */
+public class BiometricNotificationImpl implements BiometricNotification {
+
+ @Override
+ public void sendFaceEnrollNotification(@NonNull Context context) {
+ BiometricNotificationUtils.showFaceEnrollNotification(context);
+ }
+
+ @Override
+ public void sendFpEnrollNotification(@NonNull Context context) {
+ BiometricNotificationUtils.showFingerprintEnrollNotification(context);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index f516a49..2ff695d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -35,9 +35,22 @@
public class BiometricNotificationUtils {
private static final String TAG = "BiometricNotificationUtils";
- private static final String RE_ENROLL_NOTIFICATION_TAG = "FaceService";
- private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintService";
+ private static final String FACE_RE_ENROLL_NOTIFICATION_TAG = "FaceReEnroll";
+ private static final String FACE_ENROLL_NOTIFICATION_TAG = "FaceEnroll";
+ private static final String FINGERPRINT_ENROLL_NOTIFICATION_TAG = "FingerprintEnroll";
+ private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintBadCalibration";
private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
+ private static final String FACE_SETTINGS_ACTION = "android.settings.FACE_SETTINGS";
+ private static final String FINGERPRINT_SETTINGS_ACTION =
+ "android.settings.FINGERPRINT_SETTINGS";
+ private static final String FACE_ENROLL_ACTION = "android.settings.FACE_ENROLL";
+ private static final String FINGERPRINT_ENROLL_ACTION = "android.settings.FINGERPRINT_ENROLL";
+ private static final String SETTINGS_PACKAGE = "com.android.settings";
+ private static final String FACE_ENROLL_CHANNEL = "FaceEnrollNotificationChannel";
+ private static final String FACE_RE_ENROLL_CHANNEL = "FaceReEnrollNotificationChannel";
+ private static final String FINGERPRINT_ENROLL_CHANNEL = "FingerprintEnrollNotificationChannel";
+ private static final String FINGERPRINT_BAD_CALIBRATION_CHANNEL =
+ "FingerprintBadCalibrationNotificationChannel";
private static final int NOTIFICATION_ID = 1;
private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
private static long sLastAlertTime = 0;
@@ -56,18 +69,67 @@
final String content =
context.getString(R.string.face_recalibrate_notification_content);
- final Intent intent = new Intent("android.settings.FACE_SETTINGS");
- intent.setPackage("com.android.settings");
+ final Intent intent = new Intent(FACE_SETTINGS_ACTION);
+ intent.setPackage(SETTINGS_PACKAGE);
intent.putExtra(KEY_RE_ENROLL_FACE, true);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
null /* options */, UserHandle.CURRENT);
- final String channelName = "FaceEnrollNotificationChannel";
+ showNotificationHelper(context, name, title, content, pendingIntent, FACE_RE_ENROLL_CHANNEL,
+ FACE_RE_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET);
+ }
- showNotificationHelper(context, name, title, content, pendingIntent, channelName,
- RE_ENROLL_NOTIFICATION_TAG);
+ /**
+ * Shows a face enrollment notification.
+ */
+ public static void showFaceEnrollNotification(@NonNull Context context) {
+
+ final String name =
+ context.getString(R.string.device_unlock_notification_name);
+ final String title =
+ context.getString(R.string.alternative_unlock_setup_notification_title);
+ final String content =
+ context.getString(R.string.alternative_face_setup_notification_content);
+
+ final Intent intent = new Intent(FACE_ENROLL_ACTION);
+ intent.setPackage(SETTINGS_PACKAGE);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
+ 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
+ null /* options */, UserHandle.CURRENT);
+
+ showNotificationHelper(context, name, title, content, pendingIntent, FACE_ENROLL_CHANNEL,
+ FACE_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC);
+ }
+
+ /**
+ * Shows a fingerprint enrollment notification.
+ */
+ public static void showFingerprintEnrollNotification(@NonNull Context context) {
+
+ final String name =
+ context.getString(R.string.device_unlock_notification_name);
+ final String title =
+ context.getString(R.string.alternative_unlock_setup_notification_title);
+ final String content =
+ context.getString(R.string.alternative_fp_setup_notification_content);
+
+ final Intent intent = new Intent(FINGERPRINT_ENROLL_ACTION);
+ intent.setPackage(SETTINGS_PACKAGE);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
+ 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
+ null /* options */, UserHandle.CURRENT);
+
+ showNotificationHelper(context, name, title, content, pendingIntent,
+ FINGERPRINT_ENROLL_CHANNEL, FINGERPRINT_ENROLL_NOTIFICATION_TAG,
+ Notification.VISIBILITY_PUBLIC);
}
/**
@@ -93,22 +155,21 @@
final String content =
context.getString(R.string.fingerprint_recalibrate_notification_content);
- final Intent intent = new Intent("android.settings.FINGERPRINT_SETTINGS");
- intent.setPackage("com.android.settings");
+ final Intent intent = new Intent(FINGERPRINT_SETTINGS_ACTION);
+ intent.setPackage(SETTINGS_PACKAGE);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
null /* options */, UserHandle.CURRENT);
- final String channelName = "FingerprintBadCalibrationNotificationChannel";
-
- showNotificationHelper(context, name, title, content, pendingIntent, channelName,
- BAD_CALIBRATION_NOTIFICATION_TAG);
+ showNotificationHelper(context, name, title, content, pendingIntent,
+ FINGERPRINT_BAD_CALIBRATION_CHANNEL, BAD_CALIBRATION_NOTIFICATION_TAG,
+ Notification.VISIBILITY_SECRET);
}
private static void showNotificationHelper(Context context, String name, String title,
String content, PendingIntent pendingIntent, String channelName,
- String notificationTag) {
+ String notificationTag, int visibility) {
final NotificationManager notificationManager =
context.getSystemService(NotificationManager.class);
final NotificationChannel channel = new NotificationChannel(channelName, name,
@@ -123,7 +184,7 @@
.setAutoCancel(true)
.setCategory(Notification.CATEGORY_SYSTEM)
.setContentIntent(pendingIntent)
- .setVisibility(Notification.VISIBILITY_SECRET)
+ .setVisibility(visibility)
.build();
notificationManager.createNotificationChannel(channel);
@@ -134,10 +195,30 @@
/**
* Cancels a face re-enrollment notification
*/
- public static void cancelReEnrollNotification(@NonNull Context context) {
+ public static void cancelFaceReEnrollNotification(@NonNull Context context) {
final NotificationManager notificationManager =
context.getSystemService(NotificationManager.class);
- notificationManager.cancelAsUser(RE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID,
+ notificationManager.cancelAsUser(FACE_RE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+ }
+
+ /**
+ * Cancels a face enrollment notification
+ */
+ public static void cancelFaceEnrollNotification(@NonNull Context context) {
+ final NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+ notificationManager.cancelAsUser(FACE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+ }
+
+ /**
+ * Cancels a fingerprint enrollment notification
+ */
+ public static void cancelFingerprintEnrollNotification(@NonNull Context context) {
+ final NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+ notificationManager.cancelAsUser(FINGERPRINT_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID,
UserHandle.CURRENT);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 722c9af..f55cf05 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -109,7 +109,8 @@
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
- BiometricNotificationUtils.cancelReEnrollNotification(getContext());
+ BiometricNotificationUtils.cancelFaceEnrollNotification(getContext());
+ BiometricNotificationUtils.cancelFaceReEnrollNotification(getContext());
}
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index a7d160c..28f0a4d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -56,6 +56,7 @@
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -177,7 +178,7 @@
mDaemon = daemon;
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FACE);
+ BiometricsProtoEnums.MODALITY_FACE, new BiometricNotificationImpl());
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 10991d5..8086261 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -62,7 +62,7 @@
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -367,7 +367,7 @@
});
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FACE);
+ BiometricsProtoEnums.MODALITY_FACE, new BiometricNotificationImpl());
try {
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
@@ -615,8 +615,6 @@
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
- BiometricNotificationUtils.cancelReEnrollNotification(mContext);
-
final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, id, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 16d2f7a..27b9c79 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -33,6 +33,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -71,6 +72,14 @@
.getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
}
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ BiometricNotificationUtils.cancelFaceEnrollNotification(getContext());
+ BiometricNotificationUtils.cancelFaceReEnrollNotification(getContext());
+ }
+
@NonNull
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index f9e08d6..46ff6b4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -104,6 +104,13 @@
}
}
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ BiometricNotificationUtils.cancelFingerprintEnrollNotification(getContext());
+ }
+
@NonNull
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 2d062db..5f4b894 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -64,6 +64,7 @@
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -184,7 +185,7 @@
mDaemon = daemon;
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, new BiometricNotificationImpl());
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 4b07dca..d0b71fc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -66,6 +66,7 @@
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -354,7 +355,7 @@
});
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, new BiometricNotificationImpl());
try {
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 6fee84a..382e7e2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -81,6 +81,13 @@
}
}
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ BiometricNotificationUtils.cancelFingerprintEnrollNotification(getContext());
+ }
+
@NonNull
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index d57dc47..8642fb8 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,6 +16,9 @@
package com.android.server.display;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Point;
@@ -132,12 +135,15 @@
/**
* Returns the default size of the surface associated with the display, or null if the surface
* is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will
- * be the actual display device's size.
+ * be the actual display device's size, reflecting the current rotation.
*/
@Nullable
public Point getDisplaySurfaceDefaultSizeLocked() {
DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
- return new Point(displayDeviceInfo.width, displayDeviceInfo.height);
+ final boolean isRotated = mCurrentOrientation == ROTATION_90
+ || mCurrentOrientation == ROTATION_270;
+ return isRotated ? new Point(displayDeviceInfo.height, displayDeviceInfo.width)
+ : new Point(displayDeviceInfo.width, displayDeviceInfo.height);
}
/**
@@ -358,7 +364,7 @@
}
boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
- || mCurrentOrientation == Surface.ROTATION_270);
+ || mCurrentOrientation == ROTATION_270);
DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
viewport.deviceWidth = isRotated ? info.height : info.width;
viewport.deviceHeight = isRotated ? info.width : info.height;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index e5965ef..486cd28 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -2080,7 +2080,7 @@
/** Loads the refresh rate profiles. */
private void loadRefreshRateZoneProfiles(RefreshRateConfigs refreshRateConfigs) {
- if (refreshRateConfigs == null) {
+ if (refreshRateConfigs == null || refreshRateConfigs.getRefreshRateZoneProfiles() == null) {
return;
}
for (RefreshRateZone zone :
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 4edc8bc..9c271ff5 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -441,6 +441,9 @@
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED;
}
+ if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
+ mBaseDisplayInfo.flags |= Display.FLAG_ROTATES_WITH_CONTENT;
+ }
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2a617c5..6509126 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -6132,6 +6132,8 @@
mVisibilityStateComputer.dump(pw);
p.println(" mInFullscreenMode=" + mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
+ p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
+ + InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mStylusIds=" + (mStylusIds != null
? Arrays.toString(mStylusIds.toArray()) : ""));
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 15a8c0f..c24e729 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1194,7 +1194,9 @@
mNotificationRecordLogger.log(
NotificationRecordLogger.NotificationEvent.fromAction(actionIndex,
generatedByAssistant, action.isContextual()), r);
- EventLogTags.writeNotificationActionClicked(key, actionIndex,
+ EventLogTags.writeNotificationActionClicked(key,
+ action.actionIntent.getTarget().toString(),
+ action.actionIntent.getIntent().toString(), actionIndex,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
nv.rank, nv.count);
nv.recycle();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b2d3fca..100c638 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -25,8 +25,6 @@
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -48,6 +46,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.Settings;
@@ -98,8 +97,7 @@
// the period after which a notification is updated where it can make sound
private static final int MAX_SOUND_DELAY_MS = 2000;
private final StatusBarNotification sbn;
- IActivityManager mAm;
- UriGrantsManagerInternal mUgmInternal;
+ private final UriGrantsManagerInternal mUgmInternal;
final int mTargetSdkVersion;
final int mOriginalFlags;
private final Context mContext;
@@ -223,7 +221,6 @@
this.sbn = sbn;
mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
.getPackageTargetSdkVersion(sbn.getPackageName());
- mAm = ActivityManager.getService();
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mOriginalFlags = sbn.getNotification().flags;
mRankingTimeMs = calculateRankingTimeMs(0L);
@@ -1387,18 +1384,27 @@
* Collect all {@link Uri} that should have permission granted to whoever
* will be rendering it.
*/
- protected void calculateGrantableUris() {
- final Notification notification = getNotification();
- notification.visitUris((uri) -> {
- visitGrantableUri(uri, false, false);
- });
+ private void calculateGrantableUris() {
+ Trace.beginSection("NotificationRecord.calculateGrantableUris");
+ try {
+ // We can't grant URI permissions from system.
+ final int sourceUid = getSbn().getUid();
+ if (sourceUid == android.os.Process.SYSTEM_UID) return;
- if (notification.getChannelId() != null) {
- NotificationChannel channel = getChannel();
- if (channel != null) {
- visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
- & NotificationChannel.USER_LOCKED_SOUND) != 0, true);
+ final Notification notification = getNotification();
+ notification.visitUris((uri) -> {
+ visitGrantableUri(uri, false, false);
+ });
+
+ if (notification.getChannelId() != null) {
+ NotificationChannel channel = getChannel();
+ if (channel != null) {
+ visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
+ & NotificationChannel.USER_LOCKED_SOUND) != 0, true);
+ }
}
+ } finally {
+ Trace.endSection();
}
}
@@ -1413,13 +1419,14 @@
private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) {
if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
- // We can't grant Uri permissions from system
- final int sourceUid = getSbn().getUid();
- if (sourceUid == android.os.Process.SYSTEM_UID) return;
+ if (mGrantableUris != null && mGrantableUris.contains(uri)) {
+ return; // already verified this URI
+ }
+ final int sourceUid = getSbn().getUid();
final long ident = Binder.clearCallingIdentity();
try {
- // This will throw SecurityException if caller can't grant
+ // This will throw a SecurityException if the caller can't grant.
mUgmInternal.checkGrantUriPermission(sourceUid, null,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 37e4902..71502c6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -224,6 +224,9 @@
import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
+import static com.android.server.wm.StartingData.AFTER_TRANSACTION_COPY_TO_CLIENT;
+import static com.android.server.wm.StartingData.AFTER_TRANSACTION_IDLE;
+import static com.android.server.wm.StartingData.AFTER_TRANSACTION_REMOVE_DIRECTLY;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
@@ -2684,6 +2687,11 @@
if (isTransferringSplashScreen()) {
return true;
}
+ // Only do transfer after transaction has done when starting window exist.
+ if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
+ mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
+ return true;
+ }
requestCopySplashScreen();
return isTransferringSplashScreen();
}
@@ -2844,11 +2852,14 @@
if (mStartingData == null) {
return;
}
- mStartingData.mWaitForSyncTransactionCommit = false;
- if (mStartingData.mRemoveAfterTransaction) {
- mStartingData.mRemoveAfterTransaction = false;
- removeStartingWindowAnimation(mStartingData.mPrepareRemoveAnimation);
+ final StartingData lastData = mStartingData;
+ lastData.mWaitForSyncTransactionCommit = false;
+ if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
+ removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
+ } else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
+ removeStartingWindow();
}
+ lastData.mRemoveAfterTransaction = AFTER_TRANSACTION_IDLE;
}
void removeStartingWindowAnimation(boolean prepareAnimation) {
@@ -2875,7 +2886,7 @@
if (mStartingData != null) {
if (mStartingData.mWaitForSyncTransactionCommit
|| mTransitionController.inCollectingTransition(startingWindow)) {
- mStartingData.mRemoveAfterTransaction = true;
+ mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
mStartingData.mPrepareRemoveAnimation = prepareAnimation;
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fcf6587..ff2c719 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2596,9 +2596,6 @@
final int callingUid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- // When a task is locked, dismiss the root pinned task if it exists
- mRootWindowContainer.removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
-
getLockTaskController().startLockTaskMode(task, isSystemCaller, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 2eceecc..0250475 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -172,10 +172,9 @@
if (recents != null && recents.isNavigationBarAttachedToApp()) {
return;
}
- } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS) {
+ } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS
+ || mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
action = Operation.ACTION_SEAMLESS;
- } else if (mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
- return;
}
mTargetWindowTokens.put(w.mToken, new Operation(action));
return;
@@ -294,6 +293,11 @@
finishOp(mTargetWindowTokens.keyAt(i));
}
mTargetWindowTokens.clear();
+ onAllCompleted();
+ }
+
+ private void onAllCompleted() {
+ if (DEBUG) Slog.d(TAG, "onAllCompleted");
if (mTimeoutRunnable != null) {
mService.mH.removeCallbacks(mTimeoutRunnable);
}
@@ -333,7 +337,7 @@
if (DEBUG) Slog.d(TAG, "Complete directly " + token.getTopChild());
finishOp(token);
if (mTargetWindowTokens.isEmpty()) {
- if (mTimeoutRunnable != null) mService.mH.removeCallbacks(mTimeoutRunnable);
+ onAllCompleted();
return true;
}
}
@@ -411,14 +415,18 @@
if (mDisplayContent.mInputMethodWindow == null) return;
final WindowToken imeWindowToken = mDisplayContent.mInputMethodWindow.mToken;
if (isTargetToken(imeWindowToken)) return;
+ hideImmediately(imeWindowToken, Operation.ACTION_TOGGLE_IME);
+ if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
+ }
+
+ private void hideImmediately(WindowToken token, @Operation.Action int action) {
final boolean original = mHideImmediately;
mHideImmediately = true;
- final Operation op = new Operation(Operation.ACTION_TOGGLE_IME);
- mTargetWindowTokens.put(imeWindowToken, op);
- fadeWindowToken(false /* show */, imeWindowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
- op.mLeash = imeWindowToken.getAnimationLeash();
+ final Operation op = new Operation(action);
+ mTargetWindowTokens.put(token, op);
+ fadeWindowToken(false /* show */, token, ANIMATION_TYPE_TOKEN_TRANSFORM);
+ op.mLeash = token.getAnimationLeash();
mHideImmediately = original;
- if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
}
/** Returns {@code true} if the window will rotate independently. */
@@ -428,11 +436,20 @@
|| isTargetToken(w.mToken);
}
- /** Returns {@code true} if the controller will run fade animations on the window. */
+ /**
+ * Returns {@code true} if the rotation transition appearance of the window is currently
+ * managed by this controller.
+ */
boolean isTargetToken(WindowToken token) {
return mTargetWindowTokens.containsKey(token);
}
+ /** Returns {@code true} if the controller will run fade animations on the window. */
+ boolean hasFadeOperation(WindowToken token) {
+ final Operation op = mTargetWindowTokens.get(token);
+ return op != null && op.mAction == Operation.ACTION_FADE;
+ }
+
/**
* Whether the insets animation leash should use previous position when running fade animation
* or seamless transformation in a rotated display.
@@ -564,7 +581,18 @@
return false;
}
final Operation op = mTargetWindowTokens.get(w.mToken);
- if (op == null) return false;
+ if (op == null) {
+ // If a window becomes visible after the rotation transition is requested but before
+ // the transition is ready, hide it by an animation leash so it won't be flickering
+ // by drawing the rotated content before applying projection transaction of display.
+ // And it will fade in after the display transition is finished.
+ if (mTransitionOp == OP_APP_SWITCH && !mIsStartTransactionCommitted
+ && canBeAsync(w.mToken)) {
+ hideImmediately(w.mToken, Operation.ACTION_FADE);
+ if (DEBUG) Slog.d(TAG, "Hide on finishDrawing " + w.mToken.getTopChild());
+ }
+ return false;
+ }
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
if (postDrawTransaction == null || !mIsSyncDrawRequested
|| canDrawBeforeStartTransaction(op)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ee3014c..4cb4fe2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6499,6 +6499,13 @@
}
/**
+ * @return whether the physical display has a fixed orientation and cannot be rotated.
+ */
+ boolean isDisplayOrientationFixed() {
+ return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) == 0;
+ }
+
+ /**
* @return whether AOD is showing on this display
*/
boolean isAodShowing() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index ed3fad0..94df77a5 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -434,7 +434,8 @@
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
mDefaultFixedToUserRotation =
- (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode())
+ (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()
+ || mDisplayContent.isDisplayOrientationFixed())
// For debug purposes the next line turns this feature off with:
// $ adb shell setprop config.override_forced_orient true
// $ adb shell wm size reset
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 20595ea..73fdfe0 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.gui.StalledTransactionInfo;
import android.os.Debug;
import android.os.IBinder;
import android.util.Slog;
@@ -96,7 +97,7 @@
@Override
public void notifyNoFocusedWindowAnr(@NonNull InputApplicationHandle applicationHandle) {
TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchNoFocusedWindow(
- timeoutMessage("Application does not have a focused window"));
+ timeoutMessage(OptionalInt.empty(), "Application does not have a focused window"));
mService.mAnrController.notifyAppUnresponsive(applicationHandle, timeoutRecord);
}
@@ -104,7 +105,7 @@
public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
String reason) {
TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
- timeoutMessage(reason));
+ timeoutMessage(pid, reason));
mService.mAnrController.notifyWindowUnresponsive(token, pid, timeoutRecord);
}
@@ -354,11 +355,21 @@
mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
}
- private String timeoutMessage(String reason) {
- if (reason == null) {
- return "Input dispatching timed out";
+ private String timeoutMessage(OptionalInt pid, String reason) {
+ String message = (reason == null) ? "Input dispatching timed out."
+ : String.format("Input dispatching timed out (%s).", reason);
+ if (pid.isEmpty()) {
+ return message;
}
- return "Input dispatching timed out (" + reason + ")";
+ StalledTransactionInfo stalledTransactionInfo =
+ SurfaceControl.getStalledTransactionInfo(pid.getAsInt());
+ if (stalledTransactionInfo == null) {
+ return message;
+ }
+ return String.format("%s Buffer processing for the associated surface is stuck due to an "
+ + "unsignaled fence (window=%s, bufferId=0x%016X, frameNumber=%s). This "
+ + "potentially indicates a GPU hang.", message, stalledTransactionInfo.layerName,
+ stalledTransactionInfo.bufferId, stalledTransactionInfo.frameNumber);
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index ba242ec..01786be 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -969,8 +969,10 @@
final Rect innerFrame = hasInheritedLetterboxBehavior()
? mActivityRecord.getBounds() : w.getFrame();
mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint);
- // We need to notify Shell that letterbox position has changed.
- mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */);
+ if (mDoubleTapEvent) {
+ // We need to notify Shell that letterbox position has changed.
+ mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */);
+ }
} else if (mLetterbox != null) {
mLetterbox.hide();
}
@@ -1242,6 +1244,7 @@
? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT
: LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER;
logLetterboxPositionChange(changeToLog);
+ mDoubleTapEvent = true;
} else if (mLetterbox.getInnerFrame().right < x) {
// Moving to the next stop on the right side of the app window: left > center > right.
mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop(
@@ -1252,8 +1255,8 @@
? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_RIGHT
: LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER;
logLetterboxPositionChange(changeToLog);
+ mDoubleTapEvent = true;
}
- mDoubleTapEvent = true;
// TODO(197549949): Add animation for transition.
mActivityRecord.recomputeConfiguration();
}
@@ -1281,6 +1284,7 @@
? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_TOP
: LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER;
logLetterboxPositionChange(changeToLog);
+ mDoubleTapEvent = true;
} else if (mLetterbox.getInnerFrame().bottom < y) {
// Moving to the next stop on the bottom side of the app window: top > center > bottom.
mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop(
@@ -1291,8 +1295,8 @@
? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM
: LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER;
logLetterboxPositionChange(changeToLog);
+ mDoubleTapEvent = true;
}
- mDoubleTapEvent = true;
// TODO(197549949): Add animation for transition.
mActivityRecord.recomputeConfiguration();
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 0c98fb5..830f785 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.Context.STATUS_BAR_SERVICE;
@@ -669,6 +670,9 @@
}
}
+ // When a task is locked, dismiss the root pinned task if it exists
+ mSupervisor.mRootWindowContainer.removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
+
// System can only initiate screen pinning, not full lock task mode
ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index 2e5474e..79b26d2 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -86,7 +86,7 @@
ANIMATION_TYPE_TOKEN_TRANSFORM);
if (controller == null) {
fadeAnim.run();
- } else if (!controller.isTargetToken(mNavigationBar.mToken)) {
+ } else if (!controller.hasFadeOperation(mNavigationBar.mToken)) {
// If fade rotation animation is running and the nav bar is not controlled by it:
// - For fade-in animation, defer the animation until fade rotation animation finishes.
// - For fade-out animation, just play the animation.
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 34806bd..a23547e 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import android.annotation.IntDef;
+
import com.android.server.wm.StartingSurfaceController.StartingSurface;
/**
@@ -23,6 +25,20 @@
*/
public abstract class StartingData {
+ /** Nothing need to do after transaction */
+ static final int AFTER_TRANSACTION_IDLE = 0;
+ /** Remove the starting window directly after transaction done. */
+ static final int AFTER_TRANSACTION_REMOVE_DIRECTLY = 1;
+ /** Do copy splash screen to client after transaction done. */
+ static final int AFTER_TRANSACTION_COPY_TO_CLIENT = 2;
+
+ @IntDef(prefix = { "AFTER_TRANSACTION" }, value = {
+ AFTER_TRANSACTION_IDLE,
+ AFTER_TRANSACTION_REMOVE_DIRECTLY,
+ AFTER_TRANSACTION_COPY_TO_CLIENT,
+ })
+ @interface AfterTransaction {}
+
protected final WindowManagerService mService;
protected final int mTypeParams;
@@ -60,7 +76,7 @@
* This starting window should be removed after applying the start transaction of transition,
* which ensures the app window has shown.
*/
- boolean mRemoveAfterTransaction;
+ @AfterTransaction int mRemoveAfterTransaction;
/** Whether to prepare the removal animation. */
boolean mPrepareRemoveAnimation;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8fbaac2..0f0189e61 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3459,6 +3459,8 @@
info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
+ info.isUserFullscreenOverrideEnabled = top != null
+ && top.mLetterboxUiController.shouldApplyUserFullscreenOverride();
info.isFromLetterboxDoubleTap = top != null && top.mLetterboxUiController.isFromDoubleTap();
if (info.isLetterboxDoubleTapEnabled) {
info.topActivityLetterboxWidth = top.getBounds().width();
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 57ce368..f340c26 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1184,7 +1184,7 @@
}
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
- boolean deferPause) {
+ boolean skipPause) {
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canResumeByCompat()) {
return false;
@@ -1192,11 +1192,9 @@
next.delayedResume = false;
- // If we are currently pausing an activity, then don't do anything until that is done.
- final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
- if (!allPausedComplete) {
- ProtoLog.v(WM_DEBUG_STATES,
- "resumeTopActivity: Skip resume: some activity pausing.");
+ if (!skipPause && !mRootWindowContainer.allPausedActivitiesComplete()) {
+ // If we aren't skipping pause, then we have to wait for currently pausing activities.
+ ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: some activity pausing.");
return false;
}
@@ -1260,7 +1258,7 @@
lastResumed = lastFocusedRootTask.getTopResumedActivity();
}
- boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
+ boolean pausing = !skipPause && taskDisplayArea.pauseBackTasks(next);
if (mResumedActivity != null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f1fb17b..44632c9 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1930,11 +1930,6 @@
break;
}
- final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
- if (asyncRotationController != null) {
- asyncRotationController.accept(navWindow);
- }
-
if (animate) {
final NavBarFadeAnimationController controller =
new NavBarFadeAnimationController(dc);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 48cca32..5b466a0 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -1124,14 +1124,15 @@
+ "track #%d", transition.getSyncId(), track);
}
}
- if (sync) {
+ transition.mAnimationTrack = track;
+ info.setTrack(track);
+ mTrackCount = Math.max(mTrackCount, track + 1);
+ if (sync && mTrackCount > 1) {
+ // If there are >1 tracks, mark as sync so that all tracks finish.
info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Marking #%d animation as SYNC.",
transition.getSyncId());
}
- transition.mAnimationTrack = track;
- info.setTrack(track);
- mTrackCount = Math.max(mTrackCount, track + 1);
}
void updateAnimatingState(SurfaceControl.Transaction t) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index dc92376..ba13c99 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -56,7 +56,7 @@
import android.os.RemoteException;
import android.os.StatFs;
import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.Postsubmit;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -93,7 +93,7 @@
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-@Presubmit
+@Postsubmit
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
new file mode 100644
index 0000000..4fd8f26
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link DisplayDevice} class.
+ *
+ * Build/Install/Run:
+ * atest DisplayServicesTests:DisplayDeviceTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DisplayDeviceTest {
+ private final DisplayDeviceInfo mDisplayDeviceInfo = new DisplayDeviceInfo();
+ private static final int WIDTH = 500;
+ private static final int HEIGHT = 900;
+ private static final Point PORTRAIT_SIZE = new Point(WIDTH, HEIGHT);
+ private static final Point LANDSCAPE_SIZE = new Point(HEIGHT, WIDTH);
+
+ @Mock
+ private SurfaceControl.Transaction mMockTransaction;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mDisplayDeviceInfo.width = WIDTH;
+ mDisplayDeviceInfo.height = HEIGHT;
+ mDisplayDeviceInfo.rotation = ROTATION_0;
+ }
+
+ @Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_notRotated() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+ }
+
+ @Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_rotation0() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+ displayDevice.setProjectionLocked(mMockTransaction, ROTATION_0, new Rect(), new Rect());
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+ }
+
+ @Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_rotation90() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+ displayDevice.setProjectionLocked(mMockTransaction, ROTATION_90, new Rect(), new Rect());
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
+ }
+
+ @Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_rotation180() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+ displayDevice.setProjectionLocked(mMockTransaction, ROTATION_180, new Rect(), new Rect());
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+ }
+
+ @Test
+ public void testGetDisplaySurfaceDefaultSizeLocked_rotation270() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+ displayDevice.setProjectionLocked(mMockTransaction, ROTATION_270, new Rect(), new Rect());
+ assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
+ }
+
+ private static class FakeDisplayDevice extends DisplayDevice {
+ private final DisplayDeviceInfo mDisplayDeviceInfo;
+
+ FakeDisplayDevice(DisplayDeviceInfo displayDeviceInfo) {
+ super(null, null, "", InstrumentationRegistry.getInstrumentation().getContext());
+ mDisplayDeviceInfo = displayDeviceInfo;
+ }
+
+ @Override
+ public boolean hasStableUniqueId() {
+ return false;
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ return mDisplayDeviceInfo;
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d16c9c5..50cf169 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -477,6 +477,41 @@
}
@Test
+ public void testCreateVirtualRotatesWithContent() throws RemoteException {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+
+ // This is effectively the DisplayManager service published to ServiceManager.
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+ String uniqueId = "uniqueId --- Rotates with Content Test";
+ int width = 600;
+ int height = 800;
+ int dpi = 320;
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
+
+ when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+ VIRTUAL_DISPLAY_NAME, width, height, dpi);
+ builder.setFlags(flags);
+ builder.setUniqueId(uniqueId);
+ int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
+ /* projection= */ null, PACKAGE_NAME);
+ verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+ nullable(IMediaProjection.class));
+
+ displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+ // flush the handler
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+ assertNotNull(ddi);
+ assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
+ }
+
+ @Test
public void testCreateVirtualDisplayOwnFocus() throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 2065479..c0128ae 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -69,7 +69,6 @@
mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo());
mDisplayDeviceInfo.width = DISPLAY_WIDTH;
mDisplayDeviceInfo.height = DISPLAY_HEIGHT;
- mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
mDisplayDeviceInfo.modeId = MODE_ID;
mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
@@ -112,8 +111,18 @@
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
- expectedPosition.set(40, -20);
DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = DISPLAY_WIDTH;
+ displayInfo.logicalHeight = DISPLAY_HEIGHT;
+ // Rotation doesn't matter when the FLAG_ROTATES_WITH_CONTENT is absent.
+ displayInfo.rotation = Surface.ROTATION_90;
+ mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+
+ expectedPosition.set(40, -20);
+ mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+ mLogicalDisplay.updateLocked(mDeviceRepo);
displayInfo.logicalWidth = DISPLAY_HEIGHT;
displayInfo.logicalHeight = DISPLAY_WIDTH;
displayInfo.rotation = Surface.ROTATION_90;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index 99d66c5..746fb53 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -16,20 +16,42 @@
package com.android.server.biometrics;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static java.util.Collections.emptySet;
+
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.server.biometrics.sensors.BiometricNotification;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.File;
+
+@Presubmit
+@SmallTest
public class AuthenticationStatsCollectorTest {
private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -40,47 +62,220 @@
private Context mContext;
@Mock
private Resources mResources;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private FingerprintManager mFingerprintManager;
+ @Mock
+ private FaceManager mFaceManager;
+ @Mock
+ private SharedPreferences mSharedPreferences;
+ @Mock
+ private BiometricNotification mBiometricNotification;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1))
- .thenReturn(FRR_THRESHOLD);
+ when(mResources.getFraction(eq(R.fraction.config_biometricNotificationFrrThreshold),
+ anyInt(), anyInt())).thenReturn(FRR_THRESHOLD);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+ when(mContext.getSystemServiceName(FingerprintManager.class))
+ .thenReturn(Context.FINGERPRINT_SERVICE);
+ when(mContext.getSystemService(Context.FINGERPRINT_SERVICE))
+ .thenReturn(mFingerprintManager);
+ when(mContext.getSystemServiceName(FaceManager.class)).thenReturn(Context.FACE_SERVICE);
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+
+ when(mContext.getSharedPreferences(any(File.class), anyInt()))
+ .thenReturn(mSharedPreferences);
+ when(mSharedPreferences.getStringSet(anyString(), anySet())).thenReturn(emptySet());
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- 0 /* modality */);
+ 0 /* modality */, mBiometricNotification);
}
@Test
public void authenticate_authenticationSucceeded_mapShouldBeUpdated() {
// Assert that the user doesn't exist in the map initially.
- assertNull(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1));
+ assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
- mAuthenticationStatsCollector.authenticate(USER_ID_1, true /* authenticated*/);
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, true /* authenticated */);
AuthenticationStats authenticationStats =
mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1);
- assertEquals(USER_ID_1, authenticationStats.getUserId());
- assertEquals(1, authenticationStats.getTotalAttempts());
- assertEquals(0, authenticationStats.getRejectedAttempts());
- assertEquals(0, authenticationStats.getEnrollmentNotifications());
+ assertThat(authenticationStats.getUserId()).isEqualTo(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(1);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
}
@Test
public void authenticate_authenticationFailed_mapShouldBeUpdated() {
// Assert that the user doesn't exist in the map initially.
- assertNull(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1));
+ assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
- mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated*/);
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
AuthenticationStats authenticationStats =
mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1);
- assertEquals(USER_ID_1, authenticationStats.getUserId());
- assertEquals(1, authenticationStats.getTotalAttempts());
- assertEquals(1, authenticationStats.getRejectedAttempts());
- assertEquals(0, authenticationStats.getEnrollmentNotifications());
+
+ assertThat(authenticationStats.getUserId()).isEqualTo(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(1);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(1);
+ assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
+ }
+
+ @Test
+ public void authenticate_frrNotExceeded_notificationNotExceeded_shouldNotSendNotification() {
+
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 40 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that no notification should be sent.
+ verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
+ verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ }
+
+ @Test
+ public void authenticate_frrExceeded_notificationExceeded_shouldNotSendNotification() {
+
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 400 /* rejectedAttempts */, 2 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that no notification should be sent.
+ verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
+ verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ }
+
+ @Test
+ public void authenticate_frrExceeded_bothBiometricsEnrolled_shouldNotSendNotification() {
+
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that no notification should be sent.
+ verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
+ verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ }
+
+ @Test
+ public void authenticate_frrExceeded_singleModality_shouldNotSendNotification() {
+
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that no notification should be sent.
+ verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
+ verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ }
+
+ @Test
+ public void authenticate_frrExceeded_faceEnrolled_shouldSendFpNotification() {
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that fingerprint enrollment notification should be sent.
+ verify(mBiometricNotification, times(1))
+ .sendFpEnrollNotification(mContext);
+ verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ }
+
+ @Test
+ public void authenticate_frrExceeded_fpEnrolled_shouldSendFaceNotification() {
+ mAuthenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1,
+ new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */,
+ 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
+ 0 /* modality */));
+
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+ mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
+
+ // Assert that fingerprint enrollment notification should be sent.
+ verify(mBiometricNotification, times(1))
+ .sendFaceEnrollNotification(mContext);
+ verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
+ // Assert that data has been reset.
+ AuthenticationStats authenticationStats = mAuthenticationStatsCollector
+ .getAuthenticationStatsForUser(USER_ID_1);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java
new file mode 100644
index 0000000..dde2a3c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+@Presubmit
+@SmallTest
+public class AuthenticationStatsPersisterTest {
+
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private static final int USER_ID_1 = 1;
+ private static final int USER_ID_2 = 2;
+ private static final String USER_ID = "user_id";
+ private static final String FACE_ATTEMPTS = "face_attempts";
+ private static final String FACE_REJECTIONS = "face_rejections";
+ private static final String FINGERPRINT_ATTEMPTS = "fingerprint_attempts";
+ private static final String FINGERPRINT_REJECTIONS = "fingerprint_rejections";
+ private static final String ENROLLMENT_NOTIFICATIONS = "enrollment_notifications";
+ private static final String KEY = "frr_stats";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private SharedPreferences mSharedPreferences;
+ @Mock
+ private SharedPreferences.Editor mEditor;
+ private AuthenticationStatsPersister mAuthenticationStatsPersister;
+
+ @Captor
+ private ArgumentCaptor<Set<String>> mStringSetArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ when(mContext.getSharedPreferences(any(File.class), anyInt()))
+ .thenReturn(mSharedPreferences);
+ when(mSharedPreferences.edit()).thenReturn(mEditor);
+ when(mEditor.putStringSet(anyString(), anySet())).thenReturn(mEditor);
+
+ mAuthenticationStatsPersister = new AuthenticationStatsPersister(mContext);
+ }
+
+ @Test
+ public void getAllFrrStats_face_shouldListAllFrrStats() throws JSONException {
+ AuthenticationStats stats1 = new AuthenticationStats(USER_ID_1,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ AuthenticationStats stats2 = new AuthenticationStats(USER_ID_2,
+ 200 /* totalAttempts */, 20 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+ Set.of(buildFrrStats(stats1), buildFrrStats(stats2)));
+
+ List<AuthenticationStats> authenticationStatsList =
+ mAuthenticationStatsPersister.getAllFrrStats(BiometricsProtoEnums.MODALITY_FACE);
+
+ assertThat(authenticationStatsList.size()).isEqualTo(2);
+ AuthenticationStats expectedStats2 = new AuthenticationStats(USER_ID_2,
+ 0 /* totalAttempts */, 0 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ assertThat(authenticationStatsList).contains(stats1);
+ assertThat(authenticationStatsList).contains(expectedStats2);
+ }
+
+ @Test
+ public void getAllFrrStats_fingerprint_shouldListAllFrrStats() throws JSONException {
+ // User 1 with fingerprint authentication stats.
+ AuthenticationStats stats1 = new AuthenticationStats(USER_ID_1,
+ 200 /* totalAttempts */, 20 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ // User 2 without fingerprint authentication stats.
+ AuthenticationStats stats2 = new AuthenticationStats(USER_ID_2,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+ Set.of(buildFrrStats(stats1), buildFrrStats(stats2)));
+
+ List<AuthenticationStats> authenticationStatsList =
+ mAuthenticationStatsPersister
+ .getAllFrrStats(BiometricsProtoEnums.MODALITY_FINGERPRINT);
+
+ assertThat(authenticationStatsList.size()).isEqualTo(2);
+ AuthenticationStats expectedStats2 = new AuthenticationStats(USER_ID_2,
+ 0 /* totalAttempts */, 0 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ assertThat(authenticationStatsList).contains(stats1);
+ assertThat(authenticationStatsList).contains(expectedStats2);
+ }
+
+ @Test
+ public void persistFrrStats_newUser_face_shouldSuccess() throws JSONException {
+ AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+
+ mAuthenticationStatsPersister.persistFrrStats(authenticationStats.getUserId(),
+ authenticationStats.getTotalAttempts(),
+ authenticationStats.getRejectedAttempts(),
+ authenticationStats.getEnrollmentNotifications(),
+ authenticationStats.getModality());
+
+ verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+ assertThat(mStringSetArgumentCaptor.getValue())
+ .contains(buildFrrStats(authenticationStats));
+ }
+
+ @Test
+ public void persistFrrStats_newUser_fingerprint_shouldSuccess() throws JSONException {
+ AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+
+ mAuthenticationStatsPersister.persistFrrStats(authenticationStats.getUserId(),
+ authenticationStats.getTotalAttempts(),
+ authenticationStats.getRejectedAttempts(),
+ authenticationStats.getEnrollmentNotifications(),
+ authenticationStats.getModality());
+
+ verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+ assertThat(mStringSetArgumentCaptor.getValue())
+ .contains(buildFrrStats(authenticationStats));
+ }
+
+ @Test
+ public void persistFrrStats_existingUser_shouldUpdateRecord() throws JSONException {
+ AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ AuthenticationStats newAuthenticationStats = new AuthenticationStats(USER_ID_1,
+ 500 /* totalAttempts */, 30 /* rejectedAttempts */,
+ 1 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+ Set.of(buildFrrStats(authenticationStats)));
+
+ mAuthenticationStatsPersister.persistFrrStats(newAuthenticationStats.getUserId(),
+ newAuthenticationStats.getTotalAttempts(),
+ newAuthenticationStats.getRejectedAttempts(),
+ newAuthenticationStats.getEnrollmentNotifications(),
+ newAuthenticationStats.getModality());
+
+ verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+ assertThat(mStringSetArgumentCaptor.getValue())
+ .contains(buildFrrStats(newAuthenticationStats));
+ }
+
+ @Test
+ public void persistFrrStats_existingUserWithFingerprint_faceAuthenticate_shouldUpdateRecord()
+ throws JSONException {
+ // User with fingerprint authentication stats.
+ AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
+ 200 /* totalAttempts */, 20 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ // The same user with face authentication stats.
+ AuthenticationStats newAuthenticationStats = new AuthenticationStats(USER_ID_1,
+ 500 /* totalAttempts */, 30 /* rejectedAttempts */,
+ 1 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+ Set.of(buildFrrStats(authenticationStats)));
+
+ mAuthenticationStatsPersister.persistFrrStats(newAuthenticationStats.getUserId(),
+ newAuthenticationStats.getTotalAttempts(),
+ newAuthenticationStats.getRejectedAttempts(),
+ newAuthenticationStats.getEnrollmentNotifications(),
+ newAuthenticationStats.getModality());
+
+ String expectedFrrStats = new JSONObject(buildFrrStats(authenticationStats))
+ .put(ENROLLMENT_NOTIFICATIONS, newAuthenticationStats.getEnrollmentNotifications())
+ .put(FACE_ATTEMPTS, newAuthenticationStats.getTotalAttempts())
+ .put(FACE_REJECTIONS, newAuthenticationStats.getRejectedAttempts()).toString();
+ verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+ assertThat(mStringSetArgumentCaptor.getValue()).contains(expectedFrrStats);
+ }
+
+ @Test
+ public void removeFrrStats_existingUser_shouldUpdateRecord() throws JSONException {
+ AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
+ 300 /* totalAttempts */, 10 /* rejectedAttempts */,
+ 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+ when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+ Set.of(buildFrrStats(authenticationStats)));
+
+ mAuthenticationStatsPersister.removeFrrStats(USER_ID_1);
+
+ verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+ assertThat(mStringSetArgumentCaptor.getValue()).doesNotContain(authenticationStats);
+ }
+
+ private String buildFrrStats(AuthenticationStats authenticationStats)
+ throws JSONException {
+ if (authenticationStats.getModality() == BiometricsProtoEnums.MODALITY_FACE) {
+ return new JSONObject()
+ .put(USER_ID, authenticationStats.getUserId())
+ .put(FACE_ATTEMPTS, authenticationStats.getTotalAttempts())
+ .put(FACE_REJECTIONS, authenticationStats.getRejectedAttempts())
+ .put(ENROLLMENT_NOTIFICATIONS, authenticationStats.getEnrollmentNotifications())
+ .toString();
+ } else if (authenticationStats.getModality() == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+ return new JSONObject()
+ .put(USER_ID, authenticationStats.getUserId())
+ .put(FINGERPRINT_ATTEMPTS, authenticationStats.getTotalAttempts())
+ .put(FINGERPRINT_REJECTIONS, authenticationStats.getRejectedAttempts())
+ .put(ENROLLMENT_NOTIFICATIONS, authenticationStats.getEnrollmentNotifications())
+ .toString();
+ }
+ return "";
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index bdee99b..6a6fa3f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6043,6 +6043,49 @@
}
@Test
+ public void testVisitUris_styleExtrasWithoutStyle() {
+ Notification notification = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+ personWithIcon("content://user"))
+ .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+ System.currentTimeMillis(),
+ personWithIcon("content://historicalMessenger")))
+ .addMessage(new Notification.MessagingStyle.Message("Are you there",
+ System.currentTimeMillis(),
+ personWithIcon("content://messenger")))
+ .setShortcutIcon(
+ Icon.createWithContentUri("content://conversationShortcut"));
+ messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+ Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+ personWithIcon("content://caller"),
+ PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE))
+ .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+ callStyle.addExtras(notification.extras); // Same.
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ notification.visitUris(visitor);
+
+ verify(visitor).accept(eq(Uri.parse("content://user")));
+ verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+ verify(visitor).accept(eq(Uri.parse("content://messenger")));
+ verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+ verify(visitor).accept(eq(Uri.parse("content://caller")));
+ verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+ }
+
+ private static Person personWithIcon(String iconUri) {
+ return new Person.Builder()
+ .setName("Mr " + iconUri)
+ .setIcon(Icon.createWithContentUri(iconUri))
+ .build();
+ }
+
+ @Test
public void testVisitUris_wearableExtender() {
Icon actionIcon = Icon.createWithContentUri("content://media/action");
Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
@@ -7752,7 +7795,8 @@
public void testOnNotificationActionClick() {
final int actionIndex = 2;
final Notification.Action action =
- new Notification.Action.Builder(null, "text", null).build();
+ new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
+ mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
final boolean generatedByAssistant = false;
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
@@ -7776,7 +7820,8 @@
public void testOnAssistantNotificationActionClick() {
final int actionIndex = 1;
final Notification.Action action =
- new Notification.Action.Builder(null, "text", null).build();
+ new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
+ mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
final boolean generatedByAssistant = true;
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index fae92d9..f83a1df 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -36,7 +36,7 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -44,7 +44,6 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
-import android.app.IActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -76,6 +75,7 @@
import com.android.internal.R;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.LocalServices;
import com.android.server.UiServiceTestCase;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -850,84 +850,78 @@
@Test
public void testCalculateGrantableUris_PappProvided() {
- IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, ugm);
+
channel.setSound(null, null);
Notification n = new Notification.Builder(mContext, channel.getId())
.setSmallIcon(Icon.createWithContentUri(Uri.parse("content://something")))
.build();
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- record.mAm = am;
- record.mUgmInternal = ugm;
- try {
- record.calculateGrantableUris();
- fail("App provided uri for p targeting app should throw exception");
- } catch (SecurityException e) {
- // expected
- }
+ assertThrows("App provided uri for p targeting app should throw exception",
+ SecurityException.class,
+ () -> new NotificationRecord(mMockContext, sbn, channel));
}
@Test
public void testCalculateGrantableUris_PappProvided_invalidSound() {
- IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, ugm);
+
channel.setSound(Uri.parse("content://something"), mock(AudioAttributes.class));
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- record.mAm = am;
- record.mUgmInternal = ugm;
- record.calculateGrantableUris();
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
}
@Test
public void testCalculateGrantableUris_PuserOverridden() {
- IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, ugm);
+
channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- record.mAm = am;
- record.calculateGrantableUris();
+ new NotificationRecord(mMockContext, sbn, channel); // should not throw
}
@Test
public void testCalculateGrantableUris_prePappProvided() {
- IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, ugm);
+
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_O, PKG_O, id1, tag1, uid, uid, n, mUser, null, uid);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- record.mAm = am;
- record.calculateGrantableUris();
- // should not throw
+ new NotificationRecord(mMockContext, sbn, channel); // should not throw
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 7b4392b..56c3ec0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -317,7 +317,8 @@
assertEquals("Expected " + numPendingScreenshots + " pending screenshots, got "
+ mDataRequester.getPendingScreenshotCount(),
numPendingScreenshots, mDataRequester.getPendingScreenshotCount());
- assertFalse("Expected request NOT completed", mCallbacks.mRequestCompleted);
+ assertEquals("Expected request NOT completed, unless no pending data",
+ numPendingData == 0 && numPendingScreenshots == 0, mCallbacks.mRequestCompleted);
mGate.countDown();
waitForIdle(mHandler);
assertEquals("Expected " + numReceivedData + " data, received "
@@ -376,14 +377,7 @@
@Override
public void onAssistRequestCompleted() {
- mHandler.post(() -> {
- try {
- mGate.await(10, TimeUnit.SECONDS);
- mRequestCompleted = true;
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed to wait", e);
- }
- });
+ mRequestCompleted = true;
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index f757330..1617093 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -1176,6 +1176,15 @@
+ " fixed to user rotation.", mTarget.isFixedToUserRotation());
}
+ @Test
+ public void testIsFixedToUserRotation_displayContentOrientationFixed() throws Exception {
+ mBuilder.build();
+ when(mMockDisplayContent.isDisplayOrientationFixed()).thenReturn(true);
+
+ assertFalse("Display rotation should respect app requested orientation if"
+ + " the display has fixed orientation.", mTarget.isFixedToUserRotation());
+ }
+
private void moveTimeForward(long timeMillis) {
sCurrentUptimeMillis += timeMillis;
sClock.fastForward(timeMillis);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index b4f1176..7544fda 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -39,6 +39,7 @@
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_SYNC;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;
@@ -1186,6 +1187,7 @@
final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
makeWindowVisible(statusBar);
mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
+ final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
final ActivityRecord app = createActivityRecord(mDisplayContent);
final Transition transition = app.mTransitionController.createTransition(TRANSIT_OPEN);
app.mTransitionController.requestStartTransition(transition, app.getTask(),
@@ -1215,9 +1217,17 @@
mDisplayContent.mTransitionController.dispatchLegacyAppTransitionFinished(app);
assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
+ // The bar was invisible so it is not handled by the controller. But if it becomes visible
+ // and drawn before the transition starts,
+ assertFalse(asyncRotationController.isTargetToken(navBar.mToken));
+ navBar.finishDrawing(null /* postDrawTransaction */, Integer.MAX_VALUE);
+ assertTrue(asyncRotationController.isTargetToken(navBar.mToken));
+
player.startTransition();
// Non-app windows should not be collected.
assertFalse(mDisplayContent.mTransitionController.isCollecting(statusBar.mToken));
+ // Avoid DeviceStateController disturbing the test by triggering another rotation change.
+ doReturn(false).when(mDisplayContent).updateRotationUnchecked();
onRotationTransactionReady(player, mWm.mTransactionFactory.get()).onTransactionCommitted();
assertEquals(ROTATION_ANIMATION_SEAMLESS, player.mLastReady.getChange(
@@ -2384,6 +2394,37 @@
assertFalse(controller.isCollecting());
}
+ @Test
+ public void testNoSyncFlagIfOneTrack() {
+ final TransitionController controller = mAtm.getTransitionController();
+ final TestTransitionPlayer player = registerTestTransitionPlayer();
+
+ mSyncEngine = createTestBLASTSyncEngine();
+ controller.setSyncEngine(mSyncEngine);
+
+ final Transition transitA = createTestTransition(TRANSIT_OPEN, controller);
+ final Transition transitB = createTestTransition(TRANSIT_OPEN, controller);
+ final Transition transitC = createTestTransition(TRANSIT_OPEN, controller);
+
+ controller.startCollectOrQueue(transitA, (deferred) -> {});
+ controller.startCollectOrQueue(transitB, (deferred) -> {});
+ controller.startCollectOrQueue(transitC, (deferred) -> {});
+
+ // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
+ transitA.start();
+ transitA.setAllReady();
+ mSyncEngine.tryFinishForTest(transitA.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ transitB.start();
+ transitB.setAllReady();
+ mSyncEngine.tryFinishForTest(transitB.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ transitC.start();
+ transitC.setAllReady();
+ mSyncEngine.tryFinishForTest(transitC.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 58da4b43..3d78a1d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -54,6 +54,7 @@
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
+import android.service.voice.IDetectorSessionStorageService;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.ISandboxedDetectionService;
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
@@ -69,6 +70,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.server.LocalServices;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -157,6 +159,8 @@
@NonNull private ServiceConnection mRemoteVisualQueryDetectionService;
@GuardedBy("mLock")
@Nullable private IBinder mAudioFlinger;
+
+ @Nullable private IHotwordRecognitionStatusCallback mHotwordRecognitionCallback;
@GuardedBy("mLock")
private boolean mDebugHotwordLogging = false;
@@ -694,6 +698,7 @@
updateContentCaptureManager(connection);
updateSpeechService(connection);
updateServiceIdentity(connection);
+ updateStorageService(connection);
return connection;
}
}
@@ -910,6 +915,7 @@
mVoiceInteractionServiceUid, mVoiceInteractorIdentity,
mScheduledExecutorService, mDebugHotwordLogging, mRemoteExceptionListener);
}
+ mHotwordRecognitionCallback = callback;
mDetectorSessions.put(detectorType, session);
session.initialize(options, sharedMemory);
}
@@ -1035,6 +1041,23 @@
}));
}
+ private void updateStorageService(ServiceConnection connection) {
+ connection.run(service -> {
+ service.registerRemoteStorageService(new IDetectorSessionStorageService.Stub() {
+ @Override
+ public void openFile(String filename, AndroidFuture future)
+ throws RemoteException {
+ Slog.v(TAG, "BinderCallback#onFileOpen");
+ try {
+ mHotwordRecognitionCallback.onOpenFile(filename, future);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ });
+ });
+ }
+
private void addServiceUidForAudioPolicy(int uid) {
mScheduledExecutorService.execute(() -> {
AudioManagerInternal audioManager =
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 72b5159..2ccc0fa 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -39,7 +39,11 @@
"src/**/activityembedding/*.kt",
"src/**/activityembedding/open/*.kt",
"src/**/activityembedding/close/*.kt",
+ "src/**/activityembedding/layoutchange/*.kt",
+ "src/**/activityembedding/pip/*.kt",
"src/**/activityembedding/rotation/*.kt",
+ "src/**/activityembedding/rtl/*.kt",
+ "src/**/activityembedding/splitscreen/*.kt",
],
}
@@ -93,6 +97,7 @@
"flickerlib-helpers",
"platform-test-annotations",
"wm-flicker-common-app-helpers",
+ "wm-shell-flicker-utils",
],
data: [
":FlickerTestApp",
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index 4530ef3..0c36c59 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -38,7 +38,7 @@
* Setup: Launch A|B in split with B being the secondary activity. Transitions: Finish B and expect
* A to become fullscreen.
*
- * To run this test: `atest FlickerTests:CloseSecondaryActivityInSplitTest`
+ * To run this test: `atest FlickerTestsOther:CloseSecondaryActivityInSplitTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index badd876..cfc0d8b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.layoutchange
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
@@ -22,6 +22,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
@@ -38,7 +39,7 @@
* Transitions:
* Change the split ratio to A:B=0.7:0.3, expect bounds change for both A and B.
*
- * To run this test: `atest FlickerTests:HorizontalSplitChangeRatioTest`
+ * To run this test: `atest FlickerTestsOther:HorizontalSplitChangeRatioTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index 0f406fd..b0ae738 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -39,7 +39,7 @@
* Setup: Launch A|B in split with B being the secondary activity. Transitions: A start C with
* alwaysExpand=true, expect C to launch in fullscreen and cover split A|B.
*
- * To run this test: `atest FlickerTests:MainActivityStartsSecondaryWithAlwaysExpandTest`
+ * To run this test: `atest FlickerTestsOther:MainActivityStartsSecondaryWithAlwaysExpandTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index 8a997dd..48edf6d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -34,7 +34,7 @@
* Test opening an activity that will launch another activity as ActivityEmbedding placeholder in
* split.
*
- * To run this test: `atest FlickerTests:OpenActivityEmbeddingPlaceholderSplitTest`
+ * To run this test: `atest FlickerTestsOther:OpenActivityEmbeddingPlaceholderSplitTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 49aa84b..3657820 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -34,7 +34,7 @@
/**
* Test opening a secondary activity that will split with the main activity.
*
- * To run this test: `atest FlickerTests:OpenActivityEmbeddingSecondaryToSplitTest`
+ * To run this test: `atest FlickerTestsOther:OpenActivityEmbeddingSecondaryToSplitTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 404f329..5551aa6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -40,7 +40,7 @@
*
* Transitions: Let B start C, expect C to cover B and end up in split A|C.
*
- * To run this test: `atest FlickerTests:OpenThirdActivityOverSplitTest`
+ * To run this test: `atest FlickerTestsOther:OpenThirdActivityOverSplitTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index d3001d8..6432f1f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.open
import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
@@ -27,6 +27,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -42,7 +43,7 @@
* Transitions: From A launch a trampoline Activity T, T launches secondary Activity B and
* finishes itself, end up in split A|B.
*
- * To run this test: `atest FlickerTests:OpenTrampolineActivityTest`
+ * To run this test: `atest FlickerTestsOther:OpenTrampolineActivityTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 0417f9d..9ad3edd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.pip
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
@@ -25,6 +25,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -38,7 +39,7 @@
* Setup: Start from a split A|B.
* Transition: B enters PIP, observe the window shrink to the bottom right corner on screen.
*
- * To run this test: `atest FlickerTests:SecondaryActivityEnterPipTest`
+ * To run this test: `atest FlickerTestsOther:SecondaryActivityEnterPipTest`
*
*/
@RequiresDevice
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index da56500..4f7d8a4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.rotation.RotationTransition
import org.junit.FixMethodOrder
@@ -37,7 +38,7 @@
* Setup: Launch A|B in split with B being the secondary activity. Transitions: Rotate display, and
* expect A and B to split evenly in new rotation.
*
- * To run this test: `atest FlickerTests:RotateSplitNoChangeTest`
+ * To run this test: `atest FlickerTestsOther:RotateSplitNoChangeTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
index 4bc17ed..6be78f8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.rtl
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -22,6 +22,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -36,7 +37,7 @@
* PlaceholderPrimary, which is configured to launch with PlaceholderSecondary in RTL. Expect split
* PlaceholderSecondary|PlaceholderPrimary covering split B|A.
*
- * To run this test: `atest FlickerTests:RTLStartSecondaryWithPlaceholderTest`
+ * To run this test: `atest FlickerTestsOther:RTLStartSecondaryWithPlaceholderTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
new file mode 100644
index 0000000..87231c8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -0,0 +1,189 @@
+/*
+ * 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.activityembedding.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.tools.common.datatypes.Rect
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.traces.parsers.toFlickerComponent
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.utils.*
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/***
+ * Test entering System SplitScreen with Activity Embedding Split and another app.
+ *
+ * Setup: Launch A|B in split and secondaryApp, return to home.
+ * Transitions: Let AE Split A|B enter splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
+ *
+ * To run this test: `atest FlickerTestsOther:EnterSystemSplitTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class EnterSystemSplitTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
+
+ private val secondaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ testApp.launchViaIntent(wmHelper)
+ testApp.launchSecondaryActivity(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds ?:
+ error("Display not found")
+ }
+ transitions {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, testApp, secondaryApp)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, testApp, secondaryApp)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun activityEmbeddingSplitLayerBecomesVisible() {
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ testApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+ }
+
+ @Presubmit
+ @Test
+ fun activityEmbeddingSplitWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(testApp)
+
+ @Presubmit
+ @Test
+ fun secondaryLayerBecomesVisible() {
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+ }
+
+ @Presubmit
+ @Test
+ fun secondaryAppWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
+
+ /**
+ * After the transition there should be both ActivityEmbedding activities,
+ * SplitScreenPrimaryActivity and the system split divider on screen.
+ * Verify the layers are in expected sizes.
+ */
+ @Presubmit
+ @Test
+ fun activityEmbeddingSplitSurfaceAreEven() {
+ flicker.assertLayersEnd {
+ val leftAELayerRegion =
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightAELayerRegion =
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ val secondaryAppLayerRegion =
+ visibleRegion(
+ ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ val systemDivider = visibleRegion(SPLIT_SCREEN_DIVIDER_COMPONENT)
+ leftAELayerRegion
+ .plus(rightAELayerRegion.region)
+ .plus(secondaryAppLayerRegion.region)
+ .plus(systemDivider.region)
+ .coversExactly(startDisplayBounds)
+ check { "ActivityEmbeddingSplitHeight" }
+ .that(leftAELayerRegion.region.height)
+ .isEqual(rightAELayerRegion.region.height)
+ check { "SystemSplitHeight" }
+ .that(rightAELayerRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
+ // TODO(b/292283182): Remove this special case handling.
+ check { "ActivityEmbeddingSplitWidth" }
+ .that(Math.abs(
+ leftAELayerRegion.region.width - rightAELayerRegion.region.width))
+ .isLower(2)
+ check { "SystemSplitWidth" }
+ .that(Math.abs(secondaryAppLayerRegion.region.width -
+ 2 * rightAELayerRegion.region.width))
+ .isLower(2)
+ }
+ }
+
+ /**
+ * Verify the windows are in expected sizes.
+ */
+ @Presubmit
+ @Test
+ fun activityEmbeddingSplitWindowsAreEven() {
+ flicker.assertWmEnd {
+ val leftAEWindowRegion =
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightAEWindowRegion =
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ // There's no window for the divider bar.
+ val secondaryAppLayerRegion =
+ visibleRegion(
+ ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ check { "ActivityEmbeddingSplitHeight" }
+ .that(leftAEWindowRegion.region.height)
+ .isEqual(rightAEWindowRegion.region.height)
+ check { "SystemSplitHeight" }
+ .that(rightAEWindowRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
+ check { "ActivityEmbeddingSplitWidth" }
+ .that(Math.abs(
+ leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
+ .isLower(2)
+ check { "SystemSplitWidth" }
+ .that(Math.abs(secondaryAppLayerRegion.region.width -
+ 2 * rightAEWindowRegion.region.width))
+ .isLower(2)
+ }
+ }
+
+ @Ignore("Not applicable to this CUJ.")
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {}
+
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
\ No newline at end of file
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
index c9b5c96..12556bc 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
@@ -154,7 +154,7 @@
* <p>The given {@code pred} will be called on the main thread.
*/
public static void waitOnMainUntil(String message, Callable<Boolean> pred) {
- eventually(() -> assertWithMessage(message).that(pred.call()).isTrue(), TIMEOUT);
+ eventually(() -> assertWithMessage(message).that(callOnMainSync(pred)).isTrue(), TIMEOUT);
}
/** Waits until IME is shown, or throws on timeout. */
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
index 5ad3ede..c828de9f 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
@@ -196,7 +196,7 @@
public String toString() {
return new StringBuilder("SharedConnectivitySettingsState[")
.append("instantTetherEnabled=").append(mInstantTetherEnabled)
- .append("PendingIntent=").append(mInstantTetherSettingsPendingIntent.toString())
+ .append("PendingIntent=").append(mInstantTetherSettingsPendingIntent)
.append("extras=").append(mExtras.toString())
.append("]").toString();
}