Merge "Revert "Ignore wake up calls when lid closed"" into udc-dev am: d31105e09f am: a177ebf16e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23483156
Change-Id: Id951a998e9f1bd9a0ccb80e360a8a4ff56d6d0f8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 02b14ad..f8f4cc3 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -510,6 +510,17 @@
],
}
+// common protolog sources without classes that rely on Android SDK
+filegroup {
+ name: "protolog-common-no-android-src",
+ srcs: [
+ ":protolog-common-src",
+ ],
+ exclude_srcs: [
+ "com/android/internal/protolog/common/ProtoLog.java",
+ ],
+}
+
java_library {
name: "protolog-lib",
platform_apis: true,
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8021ce0..81258f1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3882,7 +3882,9 @@
* it will set up the dispatch to call {@link #onKeyUp} where the action
* will be performed; for earlier applications, it will perform the
* action immediately in on-down, as those versions of the platform
- * behaved.
+ * behaved. This implementation will also take care of {@link KeyEvent#KEYCODE_ESCAPE}
+ * by finishing the activity if it would be closed by touching outside
+ * of it.
*
* <p>Other additional default key handling may be performed
* if configured with {@link #setDefaultKeyMode}.
@@ -3904,6 +3906,11 @@
return true;
}
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE && mWindow.shouldCloseOnTouchOutside()) {
+ event.startTracking();
+ return true;
+ }
+
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
return false;
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
@@ -3999,6 +4006,15 @@
return true;
}
}
+
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE
+ && mWindow.shouldCloseOnTouchOutside()
+ && event.isTracking()
+ && !event.isCanceled()) {
+ finish();
+ return true;
+ }
+
return false;
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 411d157..4851279 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -694,12 +694,22 @@
*/
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
- && event.isTracking()
- && !event.isCanceled()
- && !WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
- onBackPressed();
- return true;
+ if (event.isTracking() && !event.isCanceled()) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
+ onBackPressed();
+ return true;
+ }
+ break;
+ case KeyEvent.KEYCODE_ESCAPE:
+ if (mCancelable) {
+ cancel();
+ } else {
+ dismiss();
+ }
+ return true;
+ }
}
return false;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2eb6ca7..8d2394b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2833,12 +2833,14 @@
}
/**
- * Note all {@link Uri} that are referenced internally, with the expectation
- * that Uri permission grants will need to be issued to ensure the recipient
- * of this object is able to render its contents.
- *
- * @hide
- */
+ * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
+ * grants will need to be issued to ensure the recipient of this object is able to render its
+ * contents.
+ * See b/281044385 for more context and examples about what happens when this isn't done
+ * correctly.
+ *
+ * @hide
+ */
public void visitUris(@NonNull Consumer<Uri> visitor) {
if (publicVersion != null) {
publicVersion.visitUris(visitor);
@@ -2882,13 +2884,13 @@
ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST, android.app.Person.class);
if (people != null && !people.isEmpty()) {
for (Person p : people) {
- visitor.accept(p.getIconUri());
+ p.visitUris(visitor);
}
}
final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
if (person != null) {
- visitor.accept(person.getIconUri());
+ person.visitUris(visitor);
}
final RemoteInputHistoryItem[] history = extras.getParcelableArray(
@@ -2910,12 +2912,7 @@
if (!ArrayUtils.isEmpty(messages)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(messages)) {
- visitor.accept(message.getDataUri());
-
- Person senderPerson = message.getSenderPerson();
- if (senderPerson != null) {
- visitor.accept(senderPerson.getIconUri());
- }
+ message.visitUris(visitor);
}
}
@@ -2924,12 +2921,7 @@
if (!ArrayUtils.isEmpty(historic)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(historic)) {
- visitor.accept(message.getDataUri());
-
- Person senderPerson = message.getSenderPerson();
- if (senderPerson != null) {
- visitor.accept(senderPerson.getIconUri());
- }
+ message.visitUris(visitor);
}
}
@@ -2939,7 +2931,7 @@
if (isStyle(CallStyle.class) & extras != null) {
Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
- visitor.accept(callPerson.getIconUri());
+ callPerson.visitUris(visitor);
}
visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
}
@@ -8833,6 +8825,18 @@
}
/**
+ * See {@link Notification#visitUris(Consumer)}.
+ *
+ * @hide
+ */
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitor.accept(getDataUri());
+ if (mSender != null) {
+ mSender.visitUris(visitor);
+ }
+ }
+
+ /**
* Returns a list of messages read from the given bundle list, e.g.
* {@link #EXTRA_MESSAGES} or {@link #EXTRA_HISTORIC_MESSAGES}.
*/
diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java
index 97a794d..18fc0ce 100644
--- a/core/java/android/app/Person.java
+++ b/core/java/android/app/Person.java
@@ -24,6 +24,7 @@
import android.os.Parcelable;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Provides an immutable reference to an entity that appears repeatedly on different surfaces of the
@@ -177,6 +178,19 @@
dest.writeBoolean(mIsBot);
}
+ /**
+ * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
+ * grants will need to be issued to ensure the recipient of this object is able to render its
+ * contents.
+ * See b/281044385 for more context and examples about what happens when this isn't done
+ * correctly.
+ *
+ * @hide
+ */
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitor.accept(getIconUri());
+ }
+
/** Builder for the immutable {@link Person} class. */
public static class Builder {
@Nullable private CharSequence mName;
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 5311b09..baf2a47 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -193,8 +193,8 @@
switch (prevState) {
// TODO(lifecycler): Extend to support all possible states.
case ON_START:
- lifecycleItem = StartActivityItem.obtain(null /* activityOptions */);
- break;
+ // Fall through to return the PAUSE item to ensure the activity is properly
+ // resumed while relaunching.
case ON_PAUSE:
lifecycleItem = PauseActivityItem.obtain();
break;
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 856bde8..36e0529 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -76,6 +76,20 @@
public final boolean disableFlushForViewTreeAppearing;
/**
+ * Is the content capture receiver enabled.
+ *
+ * @hide
+ */
+ public final boolean enableReceiver;
+
+ /**
+ * Options for the content protection flow.
+ *
+ * @hide
+ */
+ @NonNull public final ContentProtectionOptions contentProtectionOptions;
+
+ /**
* List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted
* for all acitivites in the package).
*/
@@ -94,52 +108,99 @@
* for contexts belonging to the content capture service app.
*/
public ContentCaptureOptions(int loggingLevel) {
- this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
- /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
- /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false,
+ this(
+ /* lite= */ true,
+ loggingLevel,
+ /* maxBufferSize= */ 0,
+ /* idleFlushingFrequencyMs= */ 0,
+ /* textChangeFlushingFrequencyMs= */ 0,
+ /* logHistorySize= */ 0,
+ /* disableFlushForViewTreeAppearing= */ false,
+ /* enableReceiver= */ false,
+ new ContentProtectionOptions(
+ /* enableReceiver= */ false,
+ /* bufferSize= */ 0),
/* whitelistedComponents= */ null);
}
- /**
- * Default constructor.
- */
- public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
- int textChangeFlushingFrequencyMs, int logHistorySize,
- @SuppressLint({"ConcreteCollection", "NullableCollection"})
- @Nullable ArraySet<ComponentName> whitelistedComponents) {
- this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
- textChangeFlushingFrequencyMs, logHistorySize,
+ /** Default constructor. */
+ public ContentCaptureOptions(
+ int loggingLevel,
+ int maxBufferSize,
+ int idleFlushingFrequencyMs,
+ int textChangeFlushingFrequencyMs,
+ int logHistorySize,
+ @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
+ ArraySet<ComponentName> whitelistedComponents) {
+ this(
+ /* lite= */ false,
+ loggingLevel,
+ maxBufferSize,
+ idleFlushingFrequencyMs,
+ textChangeFlushingFrequencyMs,
+ logHistorySize,
ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
+ new ContentProtectionOptions(
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
whitelistedComponents);
}
/** @hide */
- public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
- int textChangeFlushingFrequencyMs, int logHistorySize,
+ public ContentCaptureOptions(
+ int loggingLevel,
+ int maxBufferSize,
+ int idleFlushingFrequencyMs,
+ int textChangeFlushingFrequencyMs,
+ int logHistorySize,
boolean disableFlushForViewTreeAppearing,
- @SuppressLint({"ConcreteCollection", "NullableCollection"})
- @Nullable ArraySet<ComponentName> whitelistedComponents) {
- this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
- textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing,
+ boolean enableReceiver,
+ @NonNull ContentProtectionOptions contentProtectionOptions,
+ @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
+ ArraySet<ComponentName> whitelistedComponents) {
+ this(
+ /* lite= */ false,
+ loggingLevel,
+ maxBufferSize,
+ idleFlushingFrequencyMs,
+ textChangeFlushingFrequencyMs,
+ logHistorySize,
+ disableFlushForViewTreeAppearing,
+ enableReceiver,
+ contentProtectionOptions,
whitelistedComponents);
}
/** @hide */
@VisibleForTesting
public ContentCaptureOptions(@Nullable ArraySet<ComponentName> whitelistedComponents) {
- this(ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
+ this(
+ ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
+ new ContentProtectionOptions(
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
whitelistedComponents);
}
- private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
- int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
+ private ContentCaptureOptions(
+ boolean lite,
+ int loggingLevel,
+ int maxBufferSize,
+ int idleFlushingFrequencyMs,
+ int textChangeFlushingFrequencyMs,
+ int logHistorySize,
boolean disableFlushForViewTreeAppearing,
- @Nullable ArraySet<ComponentName> whitelistedComponents) {
+ boolean enableReceiver,
+ @NonNull ContentProtectionOptions contentProtectionOptions,
+ @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
+ ArraySet<ComponentName> whitelistedComponents) {
this.lite = lite;
this.loggingLevel = loggingLevel;
this.maxBufferSize = maxBufferSize;
@@ -147,6 +208,8 @@
this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
this.logHistorySize = logHistorySize;
this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing;
+ this.enableReceiver = enableReceiver;
+ this.contentProtectionOptions = contentProtectionOptions;
this.whitelistedComponents = whitelistedComponents;
}
@@ -191,12 +254,22 @@
return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
}
final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
- string.append("loggingLevel=").append(loggingLevel)
- .append(", maxBufferSize=").append(maxBufferSize)
- .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
- .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
- .append(", logHistorySize=").append(logHistorySize)
- .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing);
+ string.append("loggingLevel=")
+ .append(loggingLevel)
+ .append(", maxBufferSize=")
+ .append(maxBufferSize)
+ .append(", idleFlushingFrequencyMs=")
+ .append(idleFlushingFrequencyMs)
+ .append(", textChangeFlushingFrequencyMs=")
+ .append(textChangeFlushingFrequencyMs)
+ .append(", logHistorySize=")
+ .append(logHistorySize)
+ .append(", disableFlushForViewTreeAppearing=")
+ .append(disableFlushForViewTreeAppearing)
+ .append(", enableReceiver=")
+ .append(enableReceiver)
+ .append(", contentProtectionOptions=")
+ .append(contentProtectionOptions);
if (whitelistedComponents != null) {
string.append(", whitelisted=").append(whitelistedComponents);
}
@@ -210,11 +283,21 @@
pw.print(", lite");
return;
}
- pw.print(", bufferSize="); pw.print(maxBufferSize);
- pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
- pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
- pw.print(", logSize="); pw.print(logHistorySize);
- pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing);
+ pw.print(", bufferSize=");
+ pw.print(maxBufferSize);
+ pw.print(", idle=");
+ pw.print(idleFlushingFrequencyMs);
+ pw.print(", textIdle=");
+ pw.print(textChangeFlushingFrequencyMs);
+ pw.print(", logSize=");
+ pw.print(logHistorySize);
+ pw.print(", disableFlushForViewTreeAppearing=");
+ pw.print(disableFlushForViewTreeAppearing);
+ pw.print(", enableReceiver=");
+ pw.print(enableReceiver);
+ pw.print(", contentProtectionOptions=[");
+ contentProtectionOptions.dumpShort(pw);
+ pw.print("]");
if (whitelistedComponents != null) {
pw.print(", whitelisted="); pw.print(whitelistedComponents);
}
@@ -236,6 +319,8 @@
parcel.writeInt(textChangeFlushingFrequencyMs);
parcel.writeInt(logHistorySize);
parcel.writeBoolean(disableFlushForViewTreeAppearing);
+ parcel.writeBoolean(enableReceiver);
+ contentProtectionOptions.writeToParcel(parcel);
parcel.writeArraySet(whitelistedComponents);
}
@@ -254,12 +339,22 @@
final int textChangeFlushingFrequencyMs = parcel.readInt();
final int logHistorySize = parcel.readInt();
final boolean disableFlushForViewTreeAppearing = parcel.readBoolean();
+ final boolean enableReceiver = parcel.readBoolean();
+ final ContentProtectionOptions contentProtectionOptions =
+ ContentProtectionOptions.createFromParcel(parcel);
@SuppressWarnings("unchecked")
final ArraySet<ComponentName> whitelistedComponents =
(ArraySet<ComponentName>) parcel.readArraySet(null);
- return new ContentCaptureOptions(loggingLevel, maxBufferSize,
- idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
- disableFlushForViewTreeAppearing, whitelistedComponents);
+ return new ContentCaptureOptions(
+ loggingLevel,
+ maxBufferSize,
+ idleFlushingFrequencyMs,
+ textChangeFlushingFrequencyMs,
+ logHistorySize,
+ disableFlushForViewTreeAppearing,
+ enableReceiver,
+ contentProtectionOptions,
+ whitelistedComponents);
}
@Override
@@ -267,4 +362,62 @@
return new ContentCaptureOptions[size];
}
};
+
+ /**
+ * Content protection options for a given package.
+ *
+ * <p>Does not implement {@code Parcelable} since it is an inner class without a matching AIDL.
+ *
+ * @hide
+ */
+ public static class ContentProtectionOptions {
+
+ /**
+ * Is the content protection receiver enabled.
+ *
+ * @hide
+ */
+ public final boolean enableReceiver;
+
+ /**
+ * Size of the in-memory ring buffer for the content protection flow.
+ *
+ * @hide
+ */
+ public final int bufferSize;
+
+ public ContentProtectionOptions(boolean enableReceiver, int bufferSize) {
+ this.enableReceiver = enableReceiver;
+ this.bufferSize = bufferSize;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder("ContentProtectionOptions [");
+ stringBuilder
+ .append("enableReceiver=")
+ .append(enableReceiver)
+ .append(", bufferSize=")
+ .append(bufferSize);
+ return stringBuilder.append(']').toString();
+ }
+
+ private void dumpShort(@NonNull PrintWriter pw) {
+ pw.print("enableReceiver=");
+ pw.print(enableReceiver);
+ pw.print(", bufferSize=");
+ pw.print(bufferSize);
+ }
+
+ private void writeToParcel(Parcel parcel) {
+ parcel.writeBoolean(enableReceiver);
+ parcel.writeInt(bufferSize);
+ }
+
+ private static ContentProtectionOptions createFromParcel(Parcel parcel) {
+ boolean enableReceiver = parcel.readBoolean();
+ int bufferSize = parcel.readInt();
+ return new ContentProtectionOptions(enableReceiver, bufferSize);
+ }
+ }
}
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 17bbe14..33960c0 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -266,7 +266,7 @@
*/
public static boolean useTouchpadTapToClick(@NonNull Context context) {
return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_TAP_TO_CLICK, 0, UserHandle.USER_CURRENT) == 1;
+ Settings.System.TOUCHPAD_TAP_TO_CLICK, 1, UserHandle.USER_CURRENT) == 1;
}
/**
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index 1df9b75..18d0b09 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -110,6 +110,8 @@
private final int mOrdinal;
private final int mType;
private final int mCapabilities;
+ @Nullable
+ private final int[] mPreferredBrightnessLevels;
/**
* Creates a new light with the given data.
@@ -117,7 +119,7 @@
* @hide
*/
public Light(int id, int ordinal, int type) {
- this(id, "Light", ordinal, type, 0);
+ this(id, "Light", ordinal, type, 0, null);
}
/**
@@ -126,11 +128,22 @@
* @hide
*/
public Light(int id, String name, int ordinal, int type, int capabilities) {
+ this(id, name, ordinal, type, capabilities, null);
+ }
+
+ /**
+ * Creates a new light with the given data.
+ *
+ * @hide
+ */
+ public Light(int id, String name, int ordinal, int type, int capabilities,
+ @Nullable int[] preferredBrightnessLevels) {
mId = id;
mName = name;
mOrdinal = ordinal;
mType = type;
mCapabilities = capabilities;
+ mPreferredBrightnessLevels = preferredBrightnessLevels;
}
private Light(@NonNull Parcel in) {
@@ -139,6 +152,7 @@
mOrdinal = in.readInt();
mType = in.readInt();
mCapabilities = in.readInt();
+ mPreferredBrightnessLevels = in.createIntArray();
}
/** Implement the Parcelable interface */
@@ -149,6 +163,7 @@
dest.writeInt(mOrdinal);
dest.writeInt(mType);
dest.writeInt(mCapabilities);
+ dest.writeIntArray(mPreferredBrightnessLevels);
}
/** Implement the Parcelable interface */
@@ -252,4 +267,17 @@
return (mCapabilities & LIGHT_CAPABILITY_COLOR_RGB) == LIGHT_CAPABILITY_COLOR_RGB;
}
+ /**
+ * Returns preferred brightness levels for the light which will be used when user
+ * increase/decrease brightness levels for the light (currently only used for Keyboard
+ * backlight control using backlight up/down keys).
+ *
+ * The values in the preferred brightness level array are in the range [0, 255].
+ *
+ * @hide
+ */
+ @Nullable
+ public int[] getPreferredBrightnessLevels() {
+ return mPreferredBrightnessLevels;
+ }
}
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 9610b16..536795b 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -285,4 +285,16 @@
throw new RuntimeException(e.toString());
}
}
+
+ /**
+ * Returns the active DSU slot
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+ public String getActiveDsuSlot() {
+ try {
+ return mService.getActiveDsuSlot();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
}
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index 755368a..0280ebb 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -145,4 +145,10 @@
*/
@EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
long suggestScratchSize();
+
+ /**
+ * Get the active DSU slot
+ */
+ @EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
+ String getActiveDsuSlot();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d695c0c..d425bf8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7486,6 +7486,14 @@
public static final String STYLUS_BUTTONS_ENABLED = "stylus_buttons_enabled";
/**
+ * Preferred default user profile to use with the notes task button shortcut.
+ *
+ * @hide
+ */
+ @SuppressLint("NoSettingsProvider")
+ public static final String DEFAULT_NOTE_TASK_PROFILE = "default_note_task_profile";
+
+ /**
* Host name and port for global http proxy. Uses ':' seperator for
* between host and port.
*
@@ -17979,6 +17987,15 @@
"review_permissions_notification_state";
/**
+ * Whether repair mode is active on the device.
+ * <p>
+ * Set to 1 for true and 0 for false.
+ *
+ * @hide
+ */
+ public static final String REPAIR_MODE_ACTIVE = "repair_mode_active";
+
+ /**
* Settings migrated from Wear OS settings provider.
* @hide
*/
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index 470c280..a47f34f 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -164,6 +164,10 @@
return mFlags;
}
+ public boolean hasFlags(@Flags int mask) {
+ return (mFlags & mask) == mask;
+ }
+
public InsetsFrameProvider setInsetsSize(Insets insetsSize) {
mInsetsSize = insetsSize;
return this;
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 9fc42ff..e101849 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -58,9 +58,20 @@
*/
public static final int FLAG_SUPPRESS_SCRIM = 1;
+ /**
+ * Controls whether the insets frame will be used to move {@link RoundedCorner} inward with the
+ * insets frame size when calculating the rounded corner insets to other windows.
+ *
+ * For example, task bar will draw fake rounded corners above itself, so we need to move the
+ * rounded corner up by the task bar insets size to make other windows see a rounded corner
+ * above the task bar.
+ */
+ public static final int FLAG_INSETS_ROUNDED_CORNER = 1 << 1;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = "FLAG_", value = {
FLAG_SUPPRESS_SCRIM,
+ FLAG_INSETS_ROUNDED_CORNER,
})
public @interface Flags {}
@@ -78,7 +89,6 @@
private @Nullable Rect mVisibleFrame;
private boolean mVisible;
- private boolean mInsetsRoundedCornerFrame;
private final Rect mTmpFrame = new Rect();
@@ -98,7 +108,6 @@
? new Rect(other.mVisibleFrame)
: null;
mFlags = other.mFlags;
- mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
public void set(InsetsSource other) {
@@ -108,7 +117,6 @@
? new Rect(other.mVisibleFrame)
: null;
mFlags = other.mFlags;
- mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
public InsetsSource setFrame(int left, int top, int right, int bottom) {
@@ -136,6 +144,11 @@
return this;
}
+ public InsetsSource setFlags(@Flags int flags, @Flags int mask) {
+ mFlags = (mFlags & ~mask) | (flags & mask);
+ return this;
+ }
+
public int getId() {
return mId;
}
@@ -160,20 +173,15 @@
return mFlags;
}
+ public boolean hasFlags(int flags) {
+ return (mFlags & flags) == flags;
+ }
+
boolean isUserControllable() {
// If mVisibleFrame is null, it will be the same area as mFrame.
return mVisibleFrame == null || !mVisibleFrame.isEmpty();
}
- public boolean insetsRoundedCornerFrame() {
- return mInsetsRoundedCornerFrame;
- }
-
- public InsetsSource setInsetsRoundedCornerFrame(boolean insetsRoundedCornerFrame) {
- mInsetsRoundedCornerFrame = insetsRoundedCornerFrame;
- return this;
- }
-
/**
* Calculates the insets this source will cause to a client window.
*
@@ -317,6 +325,9 @@
if ((flags & FLAG_SUPPRESS_SCRIM) != 0) {
joiner.add("SUPPRESS_SCRIM");
}
+ if ((flags & FLAG_INSETS_ROUNDED_CORNER) != 0) {
+ joiner.add("INSETS_ROUNDED_CORNER");
+ }
return joiner.toString();
}
@@ -347,7 +358,6 @@
}
pw.print(" visible="); pw.print(mVisible);
pw.print(" flags="); pw.print(flagsToString(mFlags));
- pw.print(" insetsRoundedCornerFrame="); pw.print(mInsetsRoundedCornerFrame);
pw.println();
}
@@ -372,14 +382,12 @@
if (mFlags != that.mFlags) return false;
if (excludeInvisibleImeFrames && !mVisible && mType == WindowInsets.Type.ime()) return true;
if (!Objects.equals(mVisibleFrame, that.mVisibleFrame)) return false;
- if (mInsetsRoundedCornerFrame != that.mInsetsRoundedCornerFrame) return false;
return mFrame.equals(that.mFrame);
}
@Override
public int hashCode() {
- return Objects.hash(mId, mType, mFrame, mVisibleFrame, mVisible, mFlags,
- mInsetsRoundedCornerFrame);
+ return Objects.hash(mId, mType, mFrame, mVisibleFrame, mVisible, mFlags);
}
public InsetsSource(Parcel in) {
@@ -393,7 +401,6 @@
}
mVisible = in.readBoolean();
mFlags = in.readInt();
- mInsetsRoundedCornerFrame = in.readBoolean();
}
@Override
@@ -414,7 +421,6 @@
}
dest.writeBoolean(mVisible);
dest.writeInt(mFlags);
- dest.writeBoolean(mInsetsRoundedCornerFrame);
}
@Override
@@ -424,7 +430,6 @@
+ " mFrame=" + mFrame.toShortString()
+ " mVisible=" + mVisible
+ " mFlags=[" + flagsToString(mFlags) + "]"
- + (mInsetsRoundedCornerFrame ? " insetsRoundedCornerFrame" : "")
+ "}";
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 5b974cd..61a7277 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
import static android.view.InsetsStateProto.DISPLAY_FRAME;
import static android.view.InsetsStateProto.SOURCES;
@@ -219,7 +220,7 @@
final Rect roundedCornerFrame = new Rect(mRoundedCornerFrame);
for (int i = mSources.size() - 1; i >= 0; i--) {
final InsetsSource source = mSources.valueAt(i);
- if (source.insetsRoundedCornerFrame()) {
+ if (source.hasFlags(FLAG_INSETS_ROUNDED_CORNER)) {
final Insets insets = source.calculateInsets(roundedCornerFrame, false);
roundedCornerFrame.inset(insets);
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 1af8ca2..c703af5 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1285,6 +1285,8 @@
* </ul>
* These values are relative to the state from the last event, not accumulated, so developers
* should make sure to process this axis value for all batched historical events.
+ * <p>
+ * This axis is only set on the first pointer in a motion event.
*/
public static final int AXIS_GESTURE_X_OFFSET = 48;
@@ -1304,6 +1306,8 @@
* </ul>
* These values are relative to the state from the last event, not accumulated, so developers
* should make sure to process this axis value for all batched historical events.
+ * <p>
+ * This axis is only set on the first pointer in a motion event.
*/
public static final int AXIS_GESTURE_SCROLL_X_DISTANCE = 50;
@@ -1324,14 +1328,29 @@
* </ul>
* These values are relative to the state from the last event, not accumulated, so developers
* should make sure to process this axis value for all batched historical events.
+ * <p>
+ * This axis is only set on the first pointer in a motion event.
*/
public static final int AXIS_GESTURE_PINCH_SCALE_FACTOR = 52;
+ /**
+ * Axis constant: the number of fingers being used in a multi-finger swipe gesture.
+ * <p>
+ * <ul>
+ * <li>For a touch pad, reports the number of fingers being used in a multi-finger swipe gesture
+ * (with CLASSIFICATION_MULTI_FINGER_SWIPE).
+ * </ul>
+ * <p>
+ * Since CLASSIFICATION_MULTI_FINGER_SWIPE is a hidden API, so is this axis. It is only set on
+ * the first pointer in a motion event.
+ * @hide
+ */
+ public static final int AXIS_GESTURE_SWIPE_FINGER_COUNT = 53;
+
// NOTE: If you add a new axis here you must also add it to:
// frameworks/native/include/android/input.h
// frameworks/native/libs/input/InputEventLabels.cpp
- // platform/cts/tests/tests/view/src/android/view/cts/MotionEventTest.java
- // (testAxisFromToString)
+ // cts/tests/tests/view/src/android/view/cts/MotionEventTest.java (testAxisFromToString)
// Symbolic names of all axes.
private static final SparseArray<String> AXIS_SYMBOLIC_NAMES = new SparseArray<String>();
@@ -1387,6 +1406,7 @@
names.append(AXIS_GESTURE_SCROLL_X_DISTANCE, "AXIS_GESTURE_SCROLL_X_DISTANCE");
names.append(AXIS_GESTURE_SCROLL_Y_DISTANCE, "AXIS_GESTURE_SCROLL_Y_DISTANCE");
names.append(AXIS_GESTURE_PINCH_SCALE_FACTOR, "AXIS_GESTURE_PINCH_SCALE_FACTOR");
+ names.append(AXIS_GESTURE_SWIPE_FINGER_COUNT, "AXIS_GESTURE_SWIPE_FINGER_COUNT");
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d457847..01a99b9 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2043,7 +2043,10 @@
final float x = event.getXDispatchLocation(pointerIndex);
final float y = event.getYDispatchLocation(pointerIndex);
if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
- return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
+ // Return null here so that it fallbacks to the default PointerIcon for the source
+ // device. For mouse, the default PointerIcon is PointerIcon.TYPE_ARROW.
+ // For stylus, the default PointerIcon is PointerIcon.TYPE_NULL.
+ return null;
}
// Check what the child under the pointer says about the pointer.
final int childrenCount = mChildrenCount;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 21fe87f..7596459 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1482,6 +1482,11 @@
}
/** @hide */
+ public boolean shouldCloseOnTouchOutside() {
+ return mCloseOnTouchOutside;
+ }
+
+ /** @hide */
@SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void alwaysReadCloseOnTouchAttr();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e40f8e7..d40c032 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4252,17 +4252,6 @@
public InsetsFrameProvider[] providedInsets;
/**
- * If specified, the frame that used to calculate relative {@link RoundedCorner} will be
- * the window frame of this window minus the insets that this window provides.
- *
- * Task bar will draw fake rounded corners above itself, so we need this insets to calculate
- * correct rounded corners for this window.
- *
- * @hide
- */
- public boolean insetsRoundedCornerFrame = false;
-
- /**
* {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
* This will make layout during rotation change smoothly.
*
@@ -4718,7 +4707,6 @@
out.writeBoolean(mFitInsetsIgnoringVisibility);
out.writeBoolean(preferMinimalPostProcessing);
out.writeInt(mBlurBehindRadius);
- out.writeBoolean(insetsRoundedCornerFrame);
out.writeBoolean(mWallpaperTouchEventsEnabled);
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
checkNonRecursiveParams();
@@ -4790,7 +4778,6 @@
mFitInsetsIgnoringVisibility = in.readBoolean();
preferMinimalPostProcessing = in.readBoolean();
mBlurBehindRadius = in.readInt();
- insetsRoundedCornerFrame = in.readBoolean();
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
@@ -5098,11 +5085,6 @@
changes |= LAYOUT_CHANGED;
}
- if (insetsRoundedCornerFrame != o.insetsRoundedCornerFrame) {
- insetsRoundedCornerFrame = o.insetsRoundedCornerFrame;
- changes |= LAYOUT_CHANGED;
- }
-
if (paramsForRotation != o.paramsForRotation) {
if ((changes & LAYOUT_CHANGED) == 0) {
if (paramsForRotation != null && o.paramsForRotation != null
@@ -5340,10 +5322,6 @@
sb.append(prefix).append(" ").append(providedInsets[i]);
}
}
- if (insetsRoundedCornerFrame) {
- sb.append(" insetsRoundedCornerFrame=");
- sb.append(insetsRoundedCornerFrame);
- }
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation:");
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 668351b..c37e311 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -352,6 +352,30 @@
public static final String DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING =
"disable_flush_for_view_tree_appearing";
+ /**
+ * Enables the content protection receiver.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER =
+ "enable_content_protection_receiver";
+
+ /**
+ * Sets the size of the app blocklist for the content protection flow.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE =
+ "content_protection_apps_blocklist_size";
+
+ /**
+ * Sets the size of the in-memory ring buffer for the content protection flow.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE =
+ "content_protection_buffer_size";
+
/** @hide */
@TestApi
public static final int LOGGING_LEVEL_OFF = 0;
@@ -384,6 +408,14 @@
public static final int DEFAULT_LOG_HISTORY_SIZE = 10;
/** @hide */
public static final boolean DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = false;
+ /** @hide */
+ public static final boolean DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER = true;
+ /** @hide */
+ public static final boolean DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER = false;
+ /** @hide */
+ public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 1000;
+ /** @hide */
+ public static final int DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE = 150;
private final Object mLock = new Object();
@@ -425,11 +457,11 @@
/** @hide */
static class StrippedContext {
- final String mPackageName;
- final String mContext;
+ @NonNull final String mPackageName;
+ @NonNull final String mContext;
final @UserIdInt int mUserId;
- private StrippedContext(Context context) {
+ private StrippedContext(@NonNull Context context) {
mPackageName = context.getPackageName();
mContext = context.toString();
mUserId = context.getUserId();
@@ -440,6 +472,7 @@
return mContext;
}
+ @NonNull
public String getPackageName() {
return mPackageName;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 62044aa..b229106 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -181,6 +181,8 @@
public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9;
/** @hide */
public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10;
+ /** @hide */
+ public static final int FLUSH_REASON_LOGIN_DETECTED = 11;
/**
* After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps
@@ -191,20 +193,23 @@
static final long NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS = 258825825L;
/** @hide */
- @IntDef(prefix = { "FLUSH_REASON_" }, value = {
- FLUSH_REASON_FULL,
- FLUSH_REASON_VIEW_ROOT_ENTERED,
- FLUSH_REASON_SESSION_STARTED,
- FLUSH_REASON_SESSION_FINISHED,
- FLUSH_REASON_IDLE_TIMEOUT,
- FLUSH_REASON_TEXT_CHANGE_TIMEOUT,
- FLUSH_REASON_SESSION_CONNECTED,
- FLUSH_REASON_FORCE_FLUSH,
- FLUSH_REASON_VIEW_TREE_APPEARING,
- FLUSH_REASON_VIEW_TREE_APPEARED
- })
+ @IntDef(
+ prefix = {"FLUSH_REASON_"},
+ value = {
+ FLUSH_REASON_FULL,
+ FLUSH_REASON_VIEW_ROOT_ENTERED,
+ FLUSH_REASON_SESSION_STARTED,
+ FLUSH_REASON_SESSION_FINISHED,
+ FLUSH_REASON_IDLE_TIMEOUT,
+ FLUSH_REASON_TEXT_CHANGE_TIMEOUT,
+ FLUSH_REASON_SESSION_CONNECTED,
+ FLUSH_REASON_FORCE_FLUSH,
+ FLUSH_REASON_VIEW_TREE_APPEARING,
+ FLUSH_REASON_VIEW_TREE_APPEARED,
+ FLUSH_REASON_LOGIN_DETECTED
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface FlushReason{}
+ public @interface FlushReason {}
private final Object mLock = new Object();
@@ -685,8 +690,10 @@
return "VIEW_TREE_APPEARING";
case FLUSH_REASON_VIEW_TREE_APPEARED:
return "VIEW_TREE_APPEARED";
+ case FLUSH_REASON_LOGIN_DETECTED:
+ return "LOGIN_DETECTED";
default:
- return "UNKOWN-" + reason;
+ return "UNKNOWN-" + reason;
}
}
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 044a31f..f218995 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -480,6 +480,11 @@
return mLocaleList;
}
+ /** @hide */
+ public void setTextIdEntry(@NonNull String textIdEntry) {
+ mTextIdEntry = textIdEntry;
+ }
+
private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) {
long nodeFlags = mFlags;
diff --git a/core/java/android/view/contentprotection/ContentProtectionUtils.java b/core/java/android/view/contentprotection/ContentProtectionUtils.java
new file mode 100644
index 0000000..9abf6f1
--- /dev/null
+++ b/core/java/android/view/contentprotection/ContentProtectionUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentprotection;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ViewNode;
+
+/**
+ * Utilities for reading data from {@link ContentCaptureEvent} and {@link ViewNode}.
+ *
+ * @hide
+ */
+public final class ContentProtectionUtils {
+
+ /** Returns the text extracted directly from the {@link ContentCaptureEvent}, if set. */
+ @Nullable
+ public static String getEventText(@NonNull ContentCaptureEvent event) {
+ CharSequence text = event.getText();
+ if (text == null) {
+ return null;
+ }
+ return text.toString();
+ }
+
+ /** Returns the text extracted from the event's {@link ViewNode}, if set. */
+ @Nullable
+ public static String getViewNodeText(@NonNull ContentCaptureEvent event) {
+ ViewNode viewNode = event.getViewNode();
+ if (viewNode == null) {
+ return null;
+ }
+ return getViewNodeText(viewNode);
+ }
+
+ /** Returns the text extracted directly from the {@link ViewNode}, if set. */
+ @Nullable
+ public static String getViewNodeText(@NonNull ViewNode viewNode) {
+ CharSequence text = viewNode.getText();
+ if (text == null) {
+ return null;
+ }
+ return text.toString();
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 41ef44e..40b060a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -4361,15 +4361,14 @@
* @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
- @GuardedBy("mH")
public void dumpDebug(ProtoOutputStream proto, @Nullable byte[] icProto) {
- if (!isImeSessionAvailableLocked()) {
- return;
- }
-
- proto.write(DISPLAY_ID, mDisplayId);
- final long token = proto.start(INPUT_METHOD_MANAGER);
synchronized (mH) {
+ if (!isImeSessionAvailableLocked()) {
+ return;
+ }
+
+ proto.write(DISPLAY_ID, mDisplayId);
+ final long token = proto.start(INPUT_METHOD_MANAGER);
proto.write(CUR_ID, mCurBindState.mImeId);
proto.write(FULLSCREEN_MODE, mFullscreenMode);
proto.write(ACTIVE, mActive);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index adeb889..6ad1960 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4703,7 +4703,7 @@
@Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- if (mFastScroll != null) {
+ if (mFastScroll != null && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
PointerIcon pointerIcon = mFastScroll.onResolvePointerIcon(event, pointerIndex);
if (pointerIcon != null) {
return pointerIcon;
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 634cbe3..405099d 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.PointerIcon;
@@ -173,7 +174,8 @@
@Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- if (getPointerIcon() == null && isClickable() && isEnabled()) {
+ if (getPointerIcon() == null && isClickable() && isEnabled()
+ && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
}
return super.onResolvePointerIcon(event, pointerIndex);
diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java
index e1b0c91..b6c5396c 100644
--- a/core/java/android/widget/ImageButton.java
+++ b/core/java/android/widget/ImageButton.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.widget.RemoteViews.RemoteView;
@@ -99,7 +100,8 @@
@Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- if (getPointerIcon() == null && isClickable() && isEnabled()) {
+ if (getPointerIcon() == null && isClickable() && isEnabled()
+ && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
}
return super.onResolvePointerIcon(event, pointerIndex);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index f3600b0..edf0f48 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -38,6 +38,7 @@
import android.util.StateSet;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
@@ -1060,9 +1061,11 @@
if (!isEnabled()) {
return null;
}
- final int degrees = getDegreesFromXY(event.getX(), event.getY(), false);
- if (degrees != -1) {
- return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ final int degrees = getDegreesFromXY(event.getX(), event.getY(), false);
+ if (degrees != -1) {
+ return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+ }
}
return super.onResolvePointerIcon(event, pointerIndex);
}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 6c53a44..1317b51 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -39,6 +39,7 @@
import android.util.IntArray;
import android.util.MathUtils;
import android.util.StateSet;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
@@ -1041,12 +1042,15 @@
if (!isEnabled()) {
return null;
}
- // Add 0.5f to event coordinates to match the logic in onTouchEvent.
- final int x = (int) (event.getX() + 0.5f);
- final int y = (int) (event.getY() + 0.5f);
- final int dayUnderPointer = getDayAtLocation(x, y);
- if (dayUnderPointer >= 0) {
- return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ // Add 0.5f to event coordinates to match the logic in onTouchEvent.
+ final int x = (int) (event.getX() + 0.5f);
+ final int y = (int) (event.getY() + 0.5f);
+ final int dayUnderPointer = getDayAtLocation(x, y);
+ if (dayUnderPointer >= 0) {
+ return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+ }
}
return super.onResolvePointerIcon(event, pointerIndex);
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index ad431ef..ecc41a5 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -38,6 +38,7 @@
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
@@ -935,7 +936,8 @@
@Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- if (getPointerIcon() == null && isClickable() && isEnabled()) {
+ if (getPointerIcon() == null && isClickable() && isEnabled()
+ && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
}
return super.onResolvePointerIcon(event, pointerIndex);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index db7d484..7e1e52d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9223,18 +9223,20 @@
@Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- if (mSpannable != null && mLinksClickable) {
- final float x = event.getX(pointerIndex);
- final float y = event.getY(pointerIndex);
- final int offset = getOffsetForPosition(x, y);
- final ClickableSpan[] clickables = mSpannable.getSpans(offset, offset,
- ClickableSpan.class);
- if (clickables.length > 0) {
- return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_HAND);
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ if (mSpannable != null && mLinksClickable) {
+ final float x = event.getX(pointerIndex);
+ final float y = event.getY(pointerIndex);
+ final int offset = getOffsetForPosition(x, y);
+ final ClickableSpan[] clickables = mSpannable.getSpans(offset, offset,
+ ClickableSpan.class);
+ if (clickables.length > 0) {
+ return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_HAND);
+ }
}
- }
- if (isTextSelectable() || isTextEditable()) {
- return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_TEXT);
+ if (isTextSelectable() || isTextEditable()) {
+ return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_TEXT);
+ }
}
return super.onResolvePointerIcon(event, pointerIndex);
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 8135f9c..4cb592e 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -571,6 +571,11 @@
*/
public static final String COMBINED_BROADCAST_ENABLED = "combined_broadcast_enabled";
+ /**
+ * (boolean) Whether to allow cursor hover states for certain elements.
+ */
+ public static final String CURSOR_HOVER_STATES_ENABLED = "cursor_hover_states_enabled";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index e530aec..869b696 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -28,6 +28,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
@@ -258,8 +259,16 @@
public static final int CUJ_IME_INSETS_ANIMATION = 69;
public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70;
public static final int CUJ_LAUNCHER_OPEN_SEARCH_RESULT = 71;
+ // 72 - 77 are reserved for b/281564325.
- private static final int LAST_CUJ = CUJ_LAUNCHER_OPEN_SEARCH_RESULT;
+ /**
+ * In some cases when we do not have any end-target, we play a simple slide-down animation.
+ * eg: Open an app from Overview/Task switcher such that there is no home-screen icon.
+ * eg: Exit the app using back gesture.
+ */
+ public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
+
+ private static final int LAST_CUJ = CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
private static final int NO_STATSD_LOGGING = -1;
// Used to convert CujType to InteractionType enum value for statsd logging.
@@ -340,6 +349,14 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OPEN_SEARCH_RESULT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_SEARCH_RESULT;
+ // 72 - 77 are reserved for b/281564325.
+ CUJ_TO_STATSD_INTERACTION_TYPE[72] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[73] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[74] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[75] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[76] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
}
private static class InstanceHolder {
@@ -439,6 +456,7 @@
CUJ_IME_INSETS_ANIMATION,
CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION,
CUJ_LAUNCHER_OPEN_SEARCH_RESULT,
+ CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -1050,6 +1068,8 @@
return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
case CUJ_LAUNCHER_OPEN_SEARCH_RESULT:
return "LAUNCHER_OPEN_SEARCH_RESULT";
+ case CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK:
+ return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java
index 93765cd..8870096 100644
--- a/core/java/com/android/internal/protolog/common/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/common/ProtoLog.java
@@ -16,6 +16,8 @@
package com.android.internal.protolog.common;
+import android.util.Log;
+
/**
* ProtoLog API - exposes static logging methods. Usage of this API is similar
* to {@code android.utils.Log} class. Instead of plain text log messages each call consists of
@@ -53,6 +55,9 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.d(group.getTag(), String.format(messageString, args));
+ }
}
/**
@@ -68,6 +73,9 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.v(group.getTag(), String.format(messageString, args));
+ }
}
/**
@@ -83,6 +91,9 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.i(group.getTag(), String.format(messageString, args));
+ }
}
/**
@@ -98,6 +109,9 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.w(group.getTag(), String.format(messageString, args));
+ }
}
/**
@@ -113,6 +127,9 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.e(group.getTag(), String.format(messageString, args));
+ }
}
/**
@@ -128,5 +145,8 @@
throw new UnsupportedOperationException(
"ProtoLog calls MUST be processed with ProtoLogTool");
}
+ if (group.isLogToLogcat()) {
+ Log.wtf(group.getTag(), String.format(messageString, args));
+ }
}
}
diff --git a/core/java/com/android/internal/statusbar/IAppClipsService.aidl b/core/java/com/android/internal/statusbar/IAppClipsService.aidl
index 013d0d3..d6ab8bc 100644
--- a/core/java/com/android/internal/statusbar/IAppClipsService.aidl
+++ b/core/java/com/android/internal/statusbar/IAppClipsService.aidl
@@ -23,4 +23,6 @@
*/
interface IAppClipsService {
boolean canLaunchCaptureContentActivityForNote(in int taskId);
-}
\ No newline at end of file
+
+ int canLaunchCaptureContentActivityForNoteInternal(in int taskId);
+}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index f55d15d..fb4b026 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -163,6 +163,8 @@
@UnsupportedAppUsage
private boolean mPrintCoords = true;
+ private float mDensity;
+
public PointerLocationView(Context c) {
super(c);
setFocusableInTouchMode(true);
@@ -357,19 +359,20 @@
// Draw current touch ellipse.
mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128);
- drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor,
- ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor * mDensity,
+ ps.mCoords.touchMinor * mDensity, ps.mCoords.orientation, mPaint);
// Draw current tool ellipse.
mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel);
- drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor,
- ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor * mDensity,
+ ps.mCoords.toolMinor * mDensity, ps.mCoords.orientation, mPaint);
// Draw the orientation arrow.
float arrowSize = ps.mCoords.toolMajor * 0.7f;
if (arrowSize < 20) {
arrowSize = 20;
}
+ arrowSize *= mDensity;
mPaint.setARGB(255, pressureLevel, 255, 0);
float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation)
* arrowSize);
@@ -398,7 +401,7 @@
canvas.drawCircle(
ps.mCoords.x + orientationVectorX * tiltScale,
ps.mCoords.y + orientationVectorY * tiltScale,
- 3.0f, mPaint);
+ 3.0f * mDensity, mPaint);
// Draw the current bounding box
if (ps.mHasBoundingBox) {
@@ -1003,10 +1006,10 @@
// Compute size by display density.
private void configureDensityDependentFactors() {
- final float density = getResources().getDisplayMetrics().density;
- mTextPaint.setTextSize(10 * density);
- mPaint.setStrokeWidth(1 * density);
- mCurrentPointPaint.setStrokeWidth(1 * density);
- mPathPaint.setStrokeWidth(1 * density);
+ mDensity = getResources().getDisplayMetrics().density;
+ mTextPaint.setTextSize(10 * mDensity);
+ mPaint.setStrokeWidth(1 * mDensity);
+ mCurrentPointPaint.setStrokeWidth(1 * mDensity);
+ mPathPaint.setStrokeWidth(1 * mDensity);
}
}
diff --git a/core/proto/android/input/keyboard_configured.proto b/core/proto/android/input/keyboard_configured.proto
new file mode 100644
index 0000000..1699008
--- /dev/null
+++ b/core/proto/android/input/keyboard_configured.proto
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package com.android.internal.os;
+
+option java_outer_classname = "KeyboardConfiguredProto";
+
+/**
+ * RepeatedKeyboardLayout proto from input_extension_atoms.proto,
+ * duplicated here so that it's accessible in the build.
+ * Must be kept in sync with the version in input_extension_atoms.proto.
+ */
+
+// Message containing the repeated field for KeyboardLayoutConfig
+message RepeatedKeyboardLayoutConfig {
+ repeated KeyboardLayoutConfig keyboard_layout_config = 1;
+}
+
+// Keyboard layout configured when the device is connected
+// used in KeyboardConfigured atom
+message KeyboardLayoutConfig {
+ // Keyboard configuration details
+ // Layout type mappings found at:
+ // frameworks/base/core/res/res/values/attrs.xml
+ optional int32 keyboard_layout_type = 1;
+ // PK language language tag (e.g. en-US, ru-Cyrl, etc). This will follow
+ // BCP-47 language tag standards.
+ optional string keyboard_language_tag = 2;
+ // Selected keyboard layout name (e.g. English(US), English(Dvorak), etc.)
+ optional string keyboard_layout_name = 3;
+ // Criteria for layout selection (such as user, device, virtual keyboard based)
+ // IntDef annotation at:
+ // services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+ optional int32 layout_selection_criteria = 4;
+}
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4e22a15..a65ac57 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -702,7 +702,7 @@
<!-- no translation found for face_acquired_mouth_covering_detected (8219428572168642593) -->
<skip />
<string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"No es pot crear el model facial. Torna-ho a provar."</string>
- <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"S\'han detectat ulleres fosques. La cara ha de ser completament visible."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"S\'han detectat ulleres fosques. La cara ha de veure\'s sencera."</string>
<string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"S\'ha detectat una mascareta. La cara ha de veure\'s sencera."</string>
<string-array name="face_acquired_vendor">
</string-array>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 46202c9..f2952a0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -688,7 +688,7 @@
<string name="face_acquired_too_right" msgid="6245286514593540859">"Przesuń telefon w lewo"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"Przesuń telefon w prawo"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Patrz prosto na urządzenie."</string>
- <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie widać twarzy. Trzymaj telefon na wysokości oczu."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie widać twarzy – trzymaj telefon na wysokości oczu"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Telefon się porusza. Trzymaj go nieruchomo."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Zarejestruj swoją twarz ponownie."</string>
<string name="face_acquired_too_different" msgid="2520389515612972889">"Nie rozpoznaję twarzy. Spróbuj ponownie."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 00f8db0..8473f9b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4429,6 +4429,14 @@
-->
<string name="config_defaultContentCaptureService" translatable="false"></string>
+ <!-- The package name for the system's content protection service.
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, content protection will be
+ disabled.
+ Example: "com.android.contentprotection/.ContentProtectionService"
+ -->
+ <string name="config_defaultContentProtectionService" translatable="false"></string>
+
<!-- The package name for the system's augmented autofill service.
This service must be trusted, as it can be activated without explicit consent of the user.
If no service with the specified name exists on the device, augmented autofill wil be
@@ -6195,7 +6203,7 @@
<!-- Flag indicating whether the show Stylus pointer icon.
If set, a pointer icon will be shown over the location of a stylus pointer.-->
- <bool name="config_enableStylusPointerIcon">false</bool>
+ <bool name="config_enableStylusPointerIcon">true</bool>
<!-- Determines whether SafetyCenter feature is enabled. -->
<bool name="config_enableSafetyCenter">true</bool>
@@ -6456,4 +6464,9 @@
<!-- Whether the AOSP support for app cloning building blocks is to be enabled for the
device. -->
<bool name="config_enableAppCloningBuildingBlocks">true</bool>
+
+ <!-- Enables or disables support for repair mode. The feature creates a secure
+ environment to protect the user's privacy when the device is being repaired.
+ Off by default, since OEMs may have had a similar feature on their devices. -->
+ <bool name="config_repairModeSupported">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d70c283..9422592 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3763,6 +3763,7 @@
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
<java-symbol type="string" name="config_defaultWellbeingPackage" />
<java-symbol type="string" name="config_defaultContentCaptureService" />
+ <java-symbol type="string" name="config_defaultContentProtectionService" />
<java-symbol type="string" name="config_defaultAugmentedAutofillService" />
<java-symbol type="string" name="config_defaultTranslationService" />
<java-symbol type="string" name="config_defaultAppPredictionService" />
@@ -4913,6 +4914,8 @@
<java-symbol type="bool" name="config_safetyProtectionEnabled" />
+ <java-symbol type="bool" name="config_repairModeSupported" />
+
<java-symbol type="string" name="config_devicePolicyManagementUpdater" />
<java-symbol type="string" name="config_deviceSpecificDeviceStatePolicyProvider" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index c1deba3..129de64 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1716,6 +1716,17 @@
<meta-data android:name="android.view.im"
android:resource="@xml/ime_meta_handwriting"/>
</service>
+
+ <activity android:name="android.widget.PointerIconTestActivity"
+ android:label="PointerIconTestActivity"
+ android:screenOrientation="portrait"
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.Light">
+ <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/pointer_icon_test.xml b/core/tests/coretests/res/layout/pointer_icon_test.xml
new file mode 100644
index 0000000..a2a6447
--- /dev/null
+++ b/core/tests/coretests/res/layout/pointer_icon_test.xml
@@ -0,0 +1,59 @@
+<?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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/textview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test"/>
+
+ <EditText
+ android:id="@+id/edittext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test"/>
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test"/>
+
+ <ImageButton
+ android:id="@+id/imagebutton"
+ android:layout_width="50dp"
+ android:layout_height="50dp"/>
+
+ <Spinner
+ android:id="@+id/spinner"
+ android:layout_width="50dp"
+ android:layout_height="50dp"/>
+
+ <RadialTimePickerView
+ android:id="@+id/timepicker"
+ android:layout_width="200dp"
+ android:layout_height="200dp"/>
+
+ <CalendarView
+ android:id="@+id/calendar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
index c6f4fa2..f8348d2 100644
--- a/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
+++ b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
import android.util.ArraySet;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
@@ -40,16 +41,29 @@
@RunWith(MockitoJUnitRunner.class)
public class ContentCaptureOptionsTest {
- private final ComponentName mContextComponent = new ComponentName("marco", "polo");
- private final ComponentName mComp1 = new ComponentName("comp", "one");
- private final ComponentName mComp2 = new ComponentName("two", "comp");
+ private static final ComponentName CONTEXT_COMPONENT = new ComponentName("marco", "polo");
+ private static final ComponentName COMPONENT1 = new ComponentName("comp", "one");
+ private static final ComponentName COMPONENT2 = new ComponentName("two", "comp");
+ private static final ContentCaptureOptions CONTENT_CAPTURE_OPTIONS =
+ new ContentCaptureOptions(
+ /* loggingLevel= */ 1000,
+ /* maxBufferSize= */ 1001,
+ /* idleFlushingFrequencyMs= */ 1002,
+ /* textChangeFlushingFrequencyMs= */ 1003,
+ /* logHistorySize= */ 1004,
+ /* disableFlushForViewTreeAppearing= */ true,
+ /* enableReceiver= */ false,
+ new ContentCaptureOptions.ContentProtectionOptions(
+ /* enableReceiver= */ true,
+ /* bufferSize= */ 2001),
+ /* whitelistedComponents= */ toSet(COMPONENT1, COMPONENT2));
@Mock private Context mContext;
@Mock private ContentCaptureClient mClient;
@Before
public void setExpectation() {
- when(mClient.contentCaptureClientGetComponentName()).thenReturn(mContextComponent);
+ when(mClient.contentCaptureClientGetComponentName()).thenReturn(CONTEXT_COMPONENT);
when(mContext.getContentCaptureClient()).thenReturn(mClient);
}
@@ -67,26 +81,27 @@
@Test
public void testIsWhitelisted_notWhitelisted() {
- ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mComp2));
+ ContentCaptureOptions options = new ContentCaptureOptions(toSet(COMPONENT1, COMPONENT2));
assertThat(options.isWhitelisted(mContext)).isFalse();
}
@Test
public void testIsWhitelisted_whitelisted() {
- ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mContextComponent));
+ ContentCaptureOptions options =
+ new ContentCaptureOptions(toSet(COMPONENT1, CONTEXT_COMPONENT));
assertThat(options.isWhitelisted(mContext)).isTrue();
}
@Test
public void testIsWhitelisted_invalidContext() {
- ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
+ ContentCaptureOptions options = new ContentCaptureOptions(toSet(CONTEXT_COMPONENT));
Context invalidContext = mock(Context.class); // has no client
assertThat(options.isWhitelisted(invalidContext)).isFalse();
}
@Test
public void testIsWhitelisted_clientWithNullComponentName() {
- ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
+ ContentCaptureOptions options = new ContentCaptureOptions(toSet(CONTEXT_COMPONENT));
ContentCaptureClient client = mock(ContentCaptureClient.class);
Context context = mock(Context.class);
when(context.getContentCaptureClient()).thenReturn(client);
@@ -94,8 +109,69 @@
assertThat(options.isWhitelisted(context)).isFalse();
}
+ @Test
+ public void testToString() {
+ String actual = CONTENT_CAPTURE_OPTIONS.toString();
+
+ String expected =
+ new StringBuilder("ContentCaptureOptions [")
+ .append("loggingLevel=")
+ .append(CONTENT_CAPTURE_OPTIONS.loggingLevel)
+ .append(", maxBufferSize=")
+ .append(CONTENT_CAPTURE_OPTIONS.maxBufferSize)
+ .append(", idleFlushingFrequencyMs=")
+ .append(CONTENT_CAPTURE_OPTIONS.idleFlushingFrequencyMs)
+ .append(", textChangeFlushingFrequencyMs=")
+ .append(CONTENT_CAPTURE_OPTIONS.textChangeFlushingFrequencyMs)
+ .append(", logHistorySize=")
+ .append(CONTENT_CAPTURE_OPTIONS.logHistorySize)
+ .append(", disableFlushForViewTreeAppearing=")
+ .append(CONTENT_CAPTURE_OPTIONS.disableFlushForViewTreeAppearing)
+ .append(", enableReceiver=")
+ .append(CONTENT_CAPTURE_OPTIONS.enableReceiver)
+ .append(", contentProtectionOptions=ContentProtectionOptions [")
+ .append("enableReceiver=")
+ .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver)
+ .append(", bufferSize=")
+ .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize)
+ .append("], whitelisted=")
+ .append(CONTENT_CAPTURE_OPTIONS.whitelistedComponents)
+ .append(']')
+ .toString();
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testParcelSerializationDeserialization() {
+ Parcel parcel = Parcel.obtain();
+ CONTENT_CAPTURE_OPTIONS.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ ContentCaptureOptions actual = ContentCaptureOptions.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertThat(actual).isNotNull();
+ assertThat(actual.loggingLevel).isEqualTo(CONTENT_CAPTURE_OPTIONS.loggingLevel);
+ assertThat(actual.maxBufferSize).isEqualTo(CONTENT_CAPTURE_OPTIONS.maxBufferSize);
+ assertThat(actual.idleFlushingFrequencyMs)
+ .isEqualTo(CONTENT_CAPTURE_OPTIONS.idleFlushingFrequencyMs);
+ assertThat(actual.textChangeFlushingFrequencyMs)
+ .isEqualTo(CONTENT_CAPTURE_OPTIONS.textChangeFlushingFrequencyMs);
+ assertThat(actual.logHistorySize).isEqualTo(CONTENT_CAPTURE_OPTIONS.logHistorySize);
+ assertThat(actual.disableFlushForViewTreeAppearing)
+ .isEqualTo(CONTENT_CAPTURE_OPTIONS.disableFlushForViewTreeAppearing);
+ assertThat(actual.enableReceiver).isEqualTo(CONTENT_CAPTURE_OPTIONS.enableReceiver);
+ assertThat(actual.contentProtectionOptions).isNotNull();
+ assertThat(actual.contentProtectionOptions.enableReceiver)
+ .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver);
+ assertThat(actual.contentProtectionOptions.bufferSize)
+ .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize);
+ assertThat(actual.whitelistedComponents)
+ .containsExactlyElementsIn(CONTENT_CAPTURE_OPTIONS.whitelistedComponents);
+ }
+
@NonNull
- private ArraySet<ComponentName> toSet(@Nullable ComponentName... comps) {
+ private static ArraySet<ComponentName> toSet(@Nullable ComponentName... comps) {
ArraySet<ComponentName> set = new ArraySet<>();
if (comps != null) {
for (int i = 0; i < comps.length; i++) {
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 27d58b8..f8ebd09 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -27,6 +27,8 @@
import android.view.autofill.AutofillId;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import com.google.common.collect.ImmutableMap;
+
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -37,6 +39,8 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.Map;
+
/**
* Unit tests for {@link ContentCaptureSession}.
*
@@ -145,6 +149,35 @@
assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(1);
}
+ @Test
+ public void testGetFlushReasonAsString() {
+ int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED + 1;
+ Map<Integer, String> expectedMap =
+ new ImmutableMap.Builder<Integer, String>()
+ .put(ContentCaptureSession.FLUSH_REASON_FULL, "FULL")
+ .put(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED, "VIEW_ROOT")
+ .put(ContentCaptureSession.FLUSH_REASON_SESSION_STARTED, "STARTED")
+ .put(ContentCaptureSession.FLUSH_REASON_SESSION_FINISHED, "FINISHED")
+ .put(ContentCaptureSession.FLUSH_REASON_IDLE_TIMEOUT, "IDLE")
+ .put(ContentCaptureSession.FLUSH_REASON_TEXT_CHANGE_TIMEOUT, "TEXT_CHANGE")
+ .put(ContentCaptureSession.FLUSH_REASON_SESSION_CONNECTED, "CONNECTED")
+ .put(ContentCaptureSession.FLUSH_REASON_FORCE_FLUSH, "FORCE_FLUSH")
+ .put(
+ ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARING,
+ "VIEW_TREE_APPEARING")
+ .put(
+ ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED,
+ "VIEW_TREE_APPEARED")
+ .put(ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED, "LOGIN_DETECTED")
+ .put(invalidFlushReason, "UNKOWN-" + invalidFlushReason)
+ .build();
+
+ expectedMap.forEach(
+ (reason, expected) ->
+ assertThat(ContentCaptureSession.getFlushReasonAsString(reason))
+ .isEqualTo(expected));
+ }
+
// Cannot use @Spy because we need to pass the session id on constructor
private class MyContentCaptureSession extends ContentCaptureSession {
int mInternalNotifyViewTreeEventStartedCount = 0;
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index 93315f1..a4e77f5 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -41,49 +41,60 @@
private final Context mContext = InstrumentationRegistry.getTargetContext();
+ private final View mView = new View(mContext);
+
+ private final ViewStructureImpl mViewStructure = new ViewStructureImpl(mView);
+
+ private final ViewNode mViewNode = mViewStructure.getNode();
+
@Mock
private HtmlInfo mHtmlInfoMock;
@Test
public void testUnsupportedProperties() {
- View view = new View(mContext);
+ mViewStructure.setChildCount(1);
+ assertThat(mViewNode.getChildCount()).isEqualTo(0);
- ViewStructureImpl structure = new ViewStructureImpl(view);
- ViewNode node = structure.getNode();
+ mViewStructure.addChildCount(1);
+ assertThat(mViewNode.getChildCount()).isEqualTo(0);
- structure.setChildCount(1);
- assertThat(node.getChildCount()).isEqualTo(0);
+ assertThat(mViewStructure.newChild(0)).isNull();
+ assertThat(mViewNode.getChildCount()).isEqualTo(0);
- structure.addChildCount(1);
- assertThat(node.getChildCount()).isEqualTo(0);
+ assertThat(mViewStructure.asyncNewChild(0)).isNull();
+ assertThat(mViewNode.getChildCount()).isEqualTo(0);
- assertThat(structure.newChild(0)).isNull();
- assertThat(node.getChildCount()).isEqualTo(0);
+ mViewStructure.asyncCommit();
+ assertThat(mViewNode.getChildCount()).isEqualTo(0);
- assertThat(structure.asyncNewChild(0)).isNull();
- assertThat(node.getChildCount()).isEqualTo(0);
+ mViewStructure.setWebDomain("Y U NO SET?");
+ assertThat(mViewNode.getWebDomain()).isNull();
- structure.asyncCommit();
- assertThat(node.getChildCount()).isEqualTo(0);
+ assertThat(mViewStructure.newHtmlInfoBuilder("WHATEVER")).isNull();
- structure.setWebDomain("Y U NO SET?");
- assertThat(node.getWebDomain()).isNull();
+ mViewStructure.setHtmlInfo(mHtmlInfoMock);
+ assertThat(mViewNode.getHtmlInfo()).isNull();
- assertThat(structure.newHtmlInfoBuilder("WHATEVER")).isNull();
+ mViewStructure.setDataIsSensitive(true);
- structure.setHtmlInfo(mHtmlInfoMock);
- assertThat(node.getHtmlInfo()).isNull();
-
- structure.setDataIsSensitive(true);
-
- assertThat(structure.getTempRect()).isNull();
+ assertThat(mViewStructure.getTempRect()).isNull();
// Graphic properties
- structure.setElevation(6.66f);
- assertThat(node.getElevation()).isWithin(1.0e-10f).of(0f);
- structure.setAlpha(66.6f);
- assertThat(node.getAlpha()).isWithin(1.0e-10f).of(1.0f);
- structure.setTransformation(Matrix.IDENTITY_MATRIX);
- assertThat(node.getTransformation()).isNull();
+ mViewStructure.setElevation(6.66f);
+ assertThat(mViewNode.getElevation()).isEqualTo(0f);
+ mViewStructure.setAlpha(66.6f);
+ assertThat(mViewNode.getAlpha()).isEqualTo(1.0f);
+ mViewStructure.setTransformation(Matrix.IDENTITY_MATRIX);
+ assertThat(mViewNode.getTransformation()).isNull();
+ }
+
+ @Test
+ public void testGetSet_textIdEntry() {
+ assertThat(mViewNode.getTextIdEntry()).isNull();
+
+ String expected = "TEXT_ID_ENTRY";
+ mViewNode.setTextIdEntry(expected);
+
+ assertThat(mViewNode.getTextIdEntry()).isEqualTo(expected);
}
}
diff --git a/core/tests/coretests/src/android/view/contentprotection/ContentProtectionUtilsTest.java b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionUtilsTest.java
new file mode 100644
index 0000000..1459799
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionUtilsTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2013 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.contentprotection;
+
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.View;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ViewNode;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link ContentProtectionUtils}.
+ *
+ * <p>Run with: {@code atest
+ * FrameworksCoreTests:android.view.contentprotection.ContentProtectionUtilsTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ContentProtectionUtilsTest {
+
+ private static final String TEXT = "TEST_TEXT";
+
+ private static final ContentCaptureEvent EVENT = createEvent();
+
+ private static final ViewNode VIEW_NODE = new ViewNode();
+
+ private static final ViewNode VIEW_NODE_WITH_TEXT = createViewNodeWithText();
+
+ @Test
+ public void event_getEventText_null() {
+ String actual = ContentProtectionUtils.getEventText(EVENT);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void event_getEventText_notNull() {
+ ContentCaptureEvent event = createEvent();
+ event.setText(TEXT);
+
+ String actual = ContentProtectionUtils.getEventText(event);
+
+ assertThat(actual).isEqualTo(TEXT);
+ }
+
+ @Test
+ public void event_getViewNodeText_null() {
+ String actual = ContentProtectionUtils.getViewNodeText(EVENT);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void event_getViewNodeText_notNull() {
+ ContentCaptureEvent event = createEvent();
+ event.setViewNode(VIEW_NODE_WITH_TEXT);
+
+ String actual = ContentProtectionUtils.getViewNodeText(event);
+
+ assertThat(actual).isEqualTo(TEXT);
+ }
+
+ @Test
+ public void viewNode_getViewNodeText_null() {
+ String actual = ContentProtectionUtils.getViewNodeText(VIEW_NODE);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void viewNode_getViewNodeText_notNull() {
+ String actual = ContentProtectionUtils.getViewNodeText(VIEW_NODE_WITH_TEXT);
+
+ assertThat(actual).isEqualTo(TEXT);
+ }
+
+ private static ContentCaptureEvent createEvent() {
+ return new ContentCaptureEvent(/* sessionId= */ 123, TYPE_SESSION_STARTED);
+ }
+
+ private static ViewNode createViewNodeWithText() {
+ View view = new View(ApplicationProvider.getApplicationContext());
+ ViewStructureImpl viewStructure = new ViewStructureImpl(view);
+ viewStructure.setText(TEXT);
+ return viewStructure.getNode();
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/PointerIconTest.java b/core/tests/coretests/src/android/widget/PointerIconTest.java
new file mode 100644
index 0000000..8e9e1a5
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/PointerIconTest.java
@@ -0,0 +1,306 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.UiThread;
+import android.app.Instrumentation;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.View;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointerIconTest {
+ private Instrumentation mInstrumentation;
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ }
+
+ @Rule
+ public ActivityScenarioRule<PointerIconTestActivity> mActivityScenarioRule =
+ new ActivityScenarioRule<>(PointerIconTestActivity.class);
+
+ @Test
+ @UiThread
+ public void button_mouse_onResolvePointerIcon_returnsTypeHand() {
+ assertOnResolvePointerIconForMouseEvent(R.id.button, PointerIcon.TYPE_HAND);
+ }
+
+ @Test
+ @UiThread
+ public void button_mouse_disabled_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.button, /* enabled */ false, /* clickable */ true,
+ /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void button_mouse_unclickable_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.button, /* enabled */ true, /* clickable */ false,
+ /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void button_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.button, /* enabled */ true, /* clickable */ true,
+ /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void imageButton_mouse_onResolvePointerIconreturnsTypeHand() {
+ assertOnResolvePointerIconForMouseEvent(R.id.imagebutton, PointerIcon.TYPE_HAND);
+ }
+
+ @Test
+ @UiThread
+ public void imageButton_mouse_diabled_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.imagebutton, /* enabled */ false,
+ /* clickable */ true, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void imageButton_mouse_unclickable_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.imagebutton, /* enabled */ true,
+ /* clickable */ false, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void imageButton_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.imagebutton, /* enabled */ true,
+ /* clickable */ true, /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void textView_mouse_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.textview, /* enabled */ true,
+ /* clickable */ true, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void textView_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.textview, /* enabled */ true,
+ /* clickable */ true, /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void editText_mouse_onResolvePointerIcon_returnsTypeText() {
+ assertOnResolvePointerIconForMouseEvent(R.id.edittext, PointerIcon.TYPE_TEXT);
+ }
+
+ @Test
+ @UiThread
+ public void editText_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.edittext, /* enabled */ true,
+ /* clickable */ true, /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void spinner_mouse_onResolvePointerIcon_returnsTypeHand() {
+ assertOnResolvePointerIconForMouseEvent(R.id.spinner, PointerIcon.TYPE_HAND);
+ }
+
+ @Test
+ @UiThread
+ public void spinner_mouse_disabled_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.spinner, /* enabled */ false,
+ /* clickable */ true, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void spinner_mouse_unclickable_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.spinner, /* enabled */ true,
+ /* clickable */ false, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void spinner_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.spinner, /* enabled */ true, /* clickable */ true,
+ /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void radialTimePickerView_mouse_onResolvePointerIcon_returnsTypeHand() {
+ assertOnResolvePointerIconForMouseEvent(R.id.timepicker, PointerIcon.TYPE_HAND);
+
+ }
+
+ @Test
+ @UiThread
+ public void radialTimePickerView_mouse_disabled_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.timepicker, /* enabled */ false,
+ /* clickable */ true, /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void radialTimePickerView_stylus_onResolvePointerIcon_returnsNull() {
+ assertOnResolvePointerIconReturnNull(R.id.timepicker, /* enabled */ true,
+ /* clickable */ true, /* isMouse */ false);
+ }
+
+ @Test
+ @UiThread
+ public void calendarView_mouse_onResolvePointerIcon_returnsTypeHand() {
+ assertPointerIconForCalendarView(/* pointerType */ PointerIcon.TYPE_HAND,
+ /* isMouse */ true);
+ }
+
+ @Test
+ @UiThread
+ public void calendarView_stylus_onResolvePointerIcon_returnsNull() {
+ assertPointerIconForCalendarView(/* pointerType */ Integer.MIN_VALUE, /* isMouse */ false);
+ }
+
+ /**
+ * Assert {@link View#onResolvePointerIcon} method for {@link CalendarView}.
+ *
+ * @param pointerType the expected type of the {@link PointerIcon}.
+ * When {@link Integer#MIN_VALUE} is passed, it will verify that the
+ * returned {@link PointerIcon} is null.
+ * @param isMouse if true, mouse events are used to test the given view. Otherwise, it uses
+ * stylus events to test the view.
+ */
+ void assertPointerIconForCalendarView(int pointerType, boolean isMouse) {
+ Calendar calendar = new GregorianCalendar();
+ calendar.set(2023, 0, 1);
+ long time = calendar.getTimeInMillis();
+ mActivityScenarioRule.getScenario().onActivity(activity -> {
+ CalendarView calendarView = activity.findViewById(R.id.calendar);
+ calendarView.setDate(time, /* animate */ false, /* center */true);
+ });
+
+ // Wait for setDate to finish and then verify.
+ mInstrumentation.waitForIdleSync();
+ mActivityScenarioRule.getScenario().onActivity(activity -> {
+ CalendarView calendarView = activity.findViewById(R.id.calendar);
+ Rect bounds = new Rect();
+ calendarView.getBoundsForDate(time, bounds);
+ MotionEvent event = createHoverEvent(isMouse, bounds.centerX(), bounds.centerY());
+ PointerIcon icon = calendarView.onResolvePointerIcon(event, /* pointerIndex */ 0);
+ if (pointerType != Integer.MIN_VALUE) {
+ assertThat(icon.getType()).isEqualTo(pointerType);
+ } else {
+ assertThat(icon).isNull();
+ }
+ });
+ }
+
+ /**
+ * Assert that the given view's {@link View#onResolvePointerIcon(MotionEvent, int)} method
+ * returns a {@link PointerIcon} with the specified pointer type. The passed {@link MotionEvent}
+ * locates at the center of the view.
+ *
+ * @param resId the resource id of the view to be tested.
+ * @param pointerType the expected pointer type. When {@link Integer#MIN_VALUE} is passed, it
+ * will verify that the returned {@link PointerIcon} is null.
+ */
+ public void assertOnResolvePointerIconForMouseEvent(int resId, int pointerType) {
+ mActivityScenarioRule.getScenario().onActivity(activity -> {
+ View view = activity.findViewById(resId);
+ MotionEvent event = createHoverEvent(/* isMouse */ true, /* x */ 0, /* y */ 0);
+ PointerIcon icon = view.onResolvePointerIcon(event, /* pointerIndex */ 0);
+ if (pointerType != Integer.MIN_VALUE) {
+ assertThat(icon.getType()).isEqualTo(pointerType);
+ } else {
+ assertThat(icon).isNull();
+ }
+ });
+ }
+
+ /**
+ * Assert that the given view's {@link View#onResolvePointerIcon(MotionEvent, int)} method
+ * returns a {@link PointerIcon} with the specified pointer type. The passed {@link MotionEvent}
+ * locates at the center of the view.
+ *
+ * @param resId the resource id of the view to be tested.
+ * @param enabled whether the tested view is enabled.
+ * @param clickable whether the tested view is clickable.
+ * @param isMouse if true, mouse events are used to test the given view. Otherwise, it uses
+ * stylus events to test the view.
+ */
+ public void assertOnResolvePointerIconReturnNull(int resId, boolean enabled, boolean clickable,
+ boolean isMouse) {
+ mActivityScenarioRule.getScenario().onActivity(activity -> {
+ View view = activity.findViewById(resId);
+ view.setEnabled(enabled);
+ view.setClickable(clickable);
+ MotionEvent event = createHoverEvent(isMouse, /* x */ 0, /* y */ 0);
+ PointerIcon icon = view.onResolvePointerIcon(event, /* pointerIndex */ 0);
+ assertThat(icon).isNull();
+ });
+ }
+
+
+ /**
+ * Create a hover {@link MotionEvent} for testing.
+ *
+ * @param isMouse if true, a {@link MotionEvent} from mouse is returned. Otherwise,
+ * a {@link MotionEvent} from stylus is returned.
+ * @param x the x coordinate of the returned {@link MotionEvent}
+ * @param y the y coordinate of the returned {@link MotionEvent}
+ */
+ private MotionEvent createHoverEvent(boolean isMouse, int x, int y) {
+ MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
+ properties[0].toolType =
+ isMouse ? MotionEvent.TOOL_TYPE_MOUSE : MotionEvent.TOOL_TYPE_STYLUS;
+
+ MotionEvent.PointerCoords[] coords = MotionEvent.PointerCoords.createArray(1);
+ coords[0].x = x;
+ coords[0].y = y;
+
+ int source = isMouse ? InputDevice.SOURCE_MOUSE : InputDevice.SOURCE_STYLUS;
+ long eventTime = SystemClock.uptimeMillis();
+ return MotionEvent.obtain(/* downTime */ 0, eventTime, MotionEvent.ACTION_HOVER_MOVE,
+ /* pointerCount */ 1, properties, coords, /* metaState */ 0, /* buttonState */ 0,
+ /* xPrecision */ 1, /* yPrecision */ 1, /* deviceId */ 0, /* edgeFlags */ 0,
+ source, /* flags */ 0);
+ }
+
+}
diff --git a/core/tests/coretests/src/android/widget/PointerIconTestActivity.java b/core/tests/coretests/src/android/widget/PointerIconTestActivity.java
new file mode 100644
index 0000000..d491fb0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/PointerIconTestActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+public class PointerIconTestActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.pointer_icon_test);
+
+ RadialTimePickerView timePicker = findViewById(R.id.timepicker);
+ // Set the time of TimePicker to 0:00 so that the test is stable.
+ timePicker.setCurrentHour(0);
+ timePicker.setCurrentMinute(0);
+ }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index be2c27d..3e0e36d 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -181,7 +181,7 @@
// Verify for ON_START state. Activity should be relaunched.
getInstrumentation().runOnMainSync(() -> clientSession.startActivity(r));
- recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_START);
+ recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_PAUSE);
// Verify for ON_RESUME state. Activity should be relaunched.
getInstrumentation().runOnMainSync(() -> clientSession.resumeActivity(r));
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 89f4890..4cedd41 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -308,7 +308,8 @@
forAllTaskContainers(taskContainer -> {
synchronized (mLock) {
- final List<TaskFragmentContainer> containers = taskContainer.mContainers;
+ final List<TaskFragmentContainer> containers =
+ taskContainer.getTaskFragmentContainers();
// Clean up the TaskFragmentContainers by the z-order from the lowest.
for (int i = 0; i < containers.size(); i++) {
final TaskFragmentContainer container = containers.get(i);
@@ -611,8 +612,7 @@
@NonNull TaskContainer taskContainer) {
// Update all TaskFragments in the Task. Make a copy of the list since some may be
// removed on updating.
- final List<TaskFragmentContainer> containers =
- new ArrayList<>(taskContainer.mContainers);
+ final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
for (int i = containers.size() - 1; i >= 0; i--) {
final TaskFragmentContainer container = containers.get(i);
// Wait until onTaskFragmentAppeared to update new container.
@@ -1331,7 +1331,8 @@
// Check pending appeared activity first because there can be a delay for the server
// update.
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (container.hasPendingAppearedActivity(activityToken)) {
@@ -1342,7 +1343,8 @@
// Check appeared activity if there is no such pending appeared activity.
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (container.hasAppearedActivity(activityToken)) {
@@ -1418,7 +1420,7 @@
if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
removeExistingSecondaryContainers(wct, primaryContainer);
}
- primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer);
+ primaryContainer.getTaskContainer().addSplitContainer(splitContainer);
}
/** Cleanups all the dependencies when the TaskFragment is entering PIP. */
@@ -1430,8 +1432,9 @@
return;
}
final List<SplitContainer> splitsToRemove = new ArrayList<>();
+ final List<SplitContainer> splitContainers = taskContainer.getSplitContainers();
final Set<TaskFragmentContainer> containersToUpdate = new ArraySet<>();
- for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
+ for (SplitContainer splitContainer : splitContainers) {
if (splitContainer.getPrimaryContainer() != container
&& splitContainer.getSecondaryContainer() != container) {
continue;
@@ -1449,7 +1452,7 @@
}
}
container.resetDependencies();
- taskContainer.mSplitContainers.removeAll(splitsToRemove);
+ taskContainer.removeSplitContainers(splitsToRemove);
// If there is any TaskFragment split with the PIP TaskFragment, update their presentations
// since the split is dismissed.
// We don't want to close any of them even if they are dependencies of the PIP TaskFragment.
@@ -1471,7 +1474,7 @@
void removeContainers(@NonNull TaskContainer taskContainer,
@NonNull List<TaskFragmentContainer> containers) {
// Remove all split containers that included this one
- taskContainer.mContainers.removeAll(containers);
+ taskContainer.removeTaskFragmentContainers(containers);
// Marked as a pending removal which will be removed after it is actually removed on the
// server side (#onTaskFragmentVanished).
// In this way, we can keep track of the Task bounds until we no longer have any
@@ -1481,7 +1484,8 @@
// Cleanup any split references.
final List<SplitContainer> containersToRemove = new ArrayList<>();
- for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
+ final List<SplitContainer> splitContainers = taskContainer.getSplitContainers();
+ for (SplitContainer splitContainer : splitContainers) {
if (containersToRemove.contains(splitContainer)) {
// Don't need to check because it has been in the remove list.
continue;
@@ -1492,10 +1496,12 @@
containersToRemove.add(splitContainer);
}
}
- taskContainer.mSplitContainers.removeAll(containersToRemove);
+ taskContainer.removeSplitContainers(containersToRemove);
// Cleanup any dependent references.
- for (TaskFragmentContainer containerToUpdate : taskContainer.mContainers) {
+ final List<TaskFragmentContainer> taskFragmentContainers =
+ taskContainer.getTaskFragmentContainers();
+ for (TaskFragmentContainer containerToUpdate : taskFragmentContainers) {
containerToUpdate.removeContainersToFinishOnExit(containers);
}
}
@@ -1534,8 +1540,9 @@
if (taskContainer == null) {
return null;
}
- for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) {
- final TaskFragmentContainer container = taskContainer.mContainers.get(i);
+ final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
+ for (int i = containers.size() - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = containers.get(i);
if (!container.isFinished() && (container.getRunningActivityCount() > 0
// We may be waiting for the top TaskFragment to become non-empty after
// creation. In that case, we don't want to treat the TaskFragment below it as
@@ -1629,7 +1636,7 @@
/** Whether the given split is the topmost split in the Task. */
private boolean isTopMostSplit(@NonNull SplitContainer splitContainer) {
final List<SplitContainer> splitContainers = splitContainer.getPrimaryContainer()
- .getTaskContainer().mSplitContainers;
+ .getTaskContainer().getSplitContainers();
return splitContainer == splitContainers.get(splitContainers.size() - 1);
}
@@ -1641,7 +1648,8 @@
if (container == null) {
return null;
}
- final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers;
+ final List<SplitContainer> splitContainers =
+ container.getTaskContainer().getSplitContainers();
if (splitContainers.isEmpty()) {
return null;
}
@@ -1665,7 +1673,7 @@
@NonNull TaskFragmentContainer firstContainer,
@NonNull TaskFragmentContainer secondContainer) {
final List<SplitContainer> splitContainers = firstContainer.getTaskContainer()
- .mSplitContainers;
+ .getSplitContainers();
for (int i = splitContainers.size() - 1; i >= 0; i--) {
final SplitContainer splitContainer = splitContainers.get(i);
final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
@@ -1930,7 +1938,8 @@
@GuardedBy("mLock")
TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+ final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
+ .getTaskFragmentContainers();
for (TaskFragmentContainer container : containers) {
if (container.getTaskFragmentToken().equals(fragmentToken)) {
return container;
@@ -1945,7 +1954,7 @@
@GuardedBy("mLock")
SplitContainer getSplitContainer(@NonNull IBinder token) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<SplitContainer> containers = mTaskContainers.valueAt(i).mSplitContainers;
+ final List<SplitContainer> containers = mTaskContainers.valueAt(i).getSplitContainers();
for (SplitContainer container : containers) {
if (container.getToken().equals(token)) {
return container;
@@ -2091,7 +2100,7 @@
}
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
- .mContainers;
+ .getTaskFragmentContainers();
for (int j = containers.size() - 1; j >= 0; j--) {
final TaskFragmentContainer container = containers.get(j);
if (!container.hasActivity(activityToken)
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 4b15bb1..4580c98 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -51,11 +51,11 @@
/** Active TaskFragments in this Task. */
@NonNull
- final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+ private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
/** Active split pairs in this Task. */
@NonNull
- final List<SplitContainer> mSplitContainers = new ArrayList<>();
+ private final List<SplitContainer> mSplitContainers = new ArrayList<>();
@NonNull
private final Configuration mConfiguration;
@@ -207,6 +207,53 @@
return false;
}
+ /**
+ * Returns a list of {@link SplitContainer}. Do not modify the containers directly on the
+ * returned list. Use {@link #addSplitContainer} or {@link #removeSplitContainers} instead.
+ */
+ @NonNull
+ List<SplitContainer> getSplitContainers() {
+ return mSplitContainers;
+ }
+
+ void addSplitContainer(@NonNull SplitContainer splitContainer) {
+ mSplitContainers.add(splitContainer);
+ }
+
+ void removeSplitContainers(@NonNull List<SplitContainer> containers) {
+ mSplitContainers.removeAll(containers);
+ }
+
+ void addTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.add(taskFragmentContainer);
+ }
+
+ void addTaskFragmentContainer(int index, @NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.add(index, taskFragmentContainer);
+ }
+
+ void removeTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
+ mContainers.remove(taskFragmentContainer);
+ }
+
+ void removeTaskFragmentContainers(@NonNull List<TaskFragmentContainer> taskFragmentContainer) {
+ mContainers.removeAll(taskFragmentContainer);
+ }
+
+ void clearTaskFragmentContainer() {
+ mContainers.clear();
+ }
+
+ /**
+ * Returns a list of {@link TaskFragmentContainer}. Do not modify the containers directly on
+ * the returned list. Use {@link #addTaskFragmentContainer},
+ * {@link #removeTaskFragmentContainer} or other related methods instead.
+ */
+ @NonNull
+ List<TaskFragmentContainer> getTaskFragmentContainers() {
+ return mContainers;
+ }
+
/** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
for (SplitContainer container : mSplitContainers) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 60be9d1..61df335 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -180,23 +180,25 @@
throw new IllegalArgumentException(
"pairedPrimaryContainer must be in the same Task");
}
- final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
- taskContainer.mContainers.add(primaryIndex + 1, this);
+ final int primaryIndex = taskContainer.indexOf(pairedPrimaryContainer);
+ taskContainer.addTaskFragmentContainer(primaryIndex + 1, this);
} else if (pendingAppearedActivity != null) {
// The TaskFragment will be positioned right above the pending appeared Activity. If any
// existing TaskFragment is empty with pending Intent, it is likely that the Activity of
// the pending Intent hasn't been created yet, so the new Activity should be below the
// empty TaskFragment.
- int i = taskContainer.mContainers.size() - 1;
+ final List<TaskFragmentContainer> containers =
+ taskContainer.getTaskFragmentContainers();
+ int i = containers.size() - 1;
for (; i >= 0; i--) {
- final TaskFragmentContainer container = taskContainer.mContainers.get(i);
+ final TaskFragmentContainer container = containers.get(i);
if (!container.isEmpty() || container.getPendingAppearedIntent() == null) {
break;
}
}
- taskContainer.mContainers.add(i + 1, this);
+ taskContainer.addTaskFragmentContainer(i + 1, this);
} else {
- taskContainer.mContainers.add(this);
+ taskContainer.addTaskFragmentContainer(this);
}
if (pendingAppearedActivity != null) {
addPendingAppearedActivity(pendingAppearedActivity);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index ff08782..9e26472 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -183,23 +183,23 @@
// tf2 has running activity so is active.
final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
doReturn(1).when(tf2).getRunningActivityCount();
- taskContainer.mContainers.add(tf2);
+ taskContainer.addTaskFragmentContainer(tf2);
// tf3 is finished so is not active.
final TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
doReturn(true).when(tf3).isFinished();
doReturn(false).when(tf3).isWaitingActivityAppear();
- taskContainer.mContainers.add(tf3);
+ taskContainer.addTaskFragmentContainer(tf3);
mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
assertWithMessage("Must return tf2 because tf3 is not active.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
- taskContainer.mContainers.remove(tf3);
+ taskContainer.removeTaskFragmentContainer(tf3);
assertWithMessage("Must return tf2 because tf2 has running activity.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
- taskContainer.mContainers.remove(tf2);
+ taskContainer.removeTaskFragmentContainer(tf2);
assertWithMessage("Must return tf because we are waiting for tf1 to appear.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
@@ -320,11 +320,11 @@
doReturn(tf).when(splitContainer).getSecondaryContainer();
doReturn(createTestTaskContainer()).when(splitContainer).getTaskContainer();
doReturn(createSplitRule(mActivity, mActivity)).when(splitContainer).getSplitRule();
- final List<SplitContainer> splitContainers =
- mSplitController.getTaskContainer(TASK_ID).mSplitContainers;
- splitContainers.add(splitContainer);
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ taskContainer.addSplitContainer(splitContainer);
// Add a mock SplitContainer on top of splitContainer
- splitContainers.add(1, mock(SplitContainer.class));
+ final SplitContainer splitContainer2 = mock(SplitContainer.class);
+ taskContainer.addSplitContainer(splitContainer2);
mSplitController.updateContainer(mTransaction, tf);
@@ -332,7 +332,9 @@
// Verify if one or both containers in the top SplitContainer are finished,
// dismissPlaceholder() won't be called.
- splitContainers.remove(1);
+ final ArrayList<SplitContainer> splitContainersToRemove = new ArrayList<>();
+ splitContainersToRemove.add(splitContainer2);
+ taskContainer.removeSplitContainers(splitContainersToRemove);
doReturn(true).when(tf).isFinished();
mSplitController.updateContainer(mTransaction, tf);
@@ -363,7 +365,8 @@
final Activity r1 = createMockActivity();
addSplitTaskFragments(r0, r1);
final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
- final TaskFragmentContainer taskFragmentContainer = taskContainer.mContainers.get(0);
+ final TaskFragmentContainer taskFragmentContainer =
+ taskContainer.getTaskFragmentContainers().get(0);
spyOn(taskContainer);
// No update when the Task is invisible.
@@ -377,7 +380,7 @@
doReturn(true).when(taskContainer).isVisible();
mSplitController.updateContainer(mTransaction, taskFragmentContainer);
- verify(mSplitPresenter).updateSplitContainer(taskContainer.mSplitContainers.get(0),
+ verify(mSplitPresenter).updateSplitContainer(taskContainer.getSplitContainers().get(0),
mTransaction);
}
@@ -1090,8 +1093,8 @@
verify(mTransaction).finishActivity(mActivity.getActivityToken());
verify(mTransaction).finishActivity(secondaryActivity0.getActivityToken());
verify(mTransaction).finishActivity(secondaryActivity1.getActivityToken());
- assertTrue(taskContainer.mContainers.isEmpty());
- assertTrue(taskContainer.mSplitContainers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
+ assertTrue(taskContainer.getSplitContainers().isEmpty());
}
@Test
@@ -1363,15 +1366,13 @@
TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
tf.setInfo(mTransaction, createMockTaskFragmentInfo(tf, mActivity));
- List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
- .mContainers;
-
- assertEquals(containers.get(0), tf);
+ final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
+ assertEquals(taskContainer.getTaskFragmentContainers().get(0), tf);
mSplitController.finishActivityStacks(Collections.singleton(tf.getTaskFragmentToken()));
verify(mSplitPresenter).deleteTaskFragment(any(), eq(tf.getTaskFragmentToken()));
- assertTrue(containers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
}
@Test
@@ -1381,10 +1382,8 @@
bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity));
topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));
- List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
- .mContainers;
-
- assertEquals(containers.size(), 2);
+ final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
+ assertEquals(taskContainer.getTaskFragmentContainers().size(), 2);
Set<IBinder> activityStackTokens = new ArraySet<>(new IBinder[]{
topTf.getTaskFragmentToken(), bottomTf.getTaskFragmentToken()});
@@ -1403,7 +1402,7 @@
+ "regardless of the order in ActivityStack set",
topTf.getTaskFragmentToken(), fragmentTokens.get(1));
- assertTrue(containers.isEmpty());
+ assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
}
@Test
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 13e7092..11af1d1 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -127,7 +127,7 @@
assertFalse(taskContainer.isEmpty());
taskContainer.mFinishedContainer.add(tf.getTaskFragmentToken());
- taskContainer.mContainers.clear();
+ taskContainer.clearTaskFragmentContainer();
assertFalse(taskContainer.isEmpty());
}
@@ -152,13 +152,13 @@
assertNull(taskContainer.getTopNonFinishingActivity());
final TaskFragmentContainer tf0 = mock(TaskFragmentContainer.class);
- taskContainer.mContainers.add(tf0);
+ taskContainer.addTaskFragmentContainer(tf0);
final Activity activity0 = mock(Activity.class);
doReturn(activity0).when(tf0).getTopNonFinishingActivity();
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
final TaskFragmentContainer tf1 = mock(TaskFragmentContainer.class);
- taskContainer.mContainers.add(tf1);
+ taskContainer.addTaskFragmentContainer(tf1);
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
final Activity activity1 = mock(Activity.class);
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml
new file mode 100644
index 0000000..d99d64d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_section.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <ripple android:color="#99999999">
+ <item android:drawable="@drawable/bubble_manage_menu_bg" />
+ </ripple>
+ </item>
+ <item android:drawable="@drawable/bubble_manage_menu_bg" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml b/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml
new file mode 100644
index 0000000..f450846
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/ic_expand_less.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18.59,16.41L20,15L12,7L4,15L5.41,16.41L12,9.83"
+ android:fillColor="#5F6368"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml
new file mode 100644
index 0000000..ddcd5c6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.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.bubbles.bar.BubbleBarMenuItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_height"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
+ android:background="@drawable/bubble_manage_menu_row">
+
+ <ImageView
+ android:id="@+id/bubble_bar_menu_item_icon"
+ android:layout_width="@dimen/bubble_bar_manage_menu_item_icon_size"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_icon_size"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@+id/bubble_bar_menu_item_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault" />
+
+</com.android.wm.shell.bubbles.bar.BubbleBarMenuItemView>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
new file mode 100644
index 0000000..82e5aee
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.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
+ -->
+<com.android.wm.shell.bubbles.bar.BubbleBarMenuView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:minWidth="@dimen/bubble_bar_manage_menu_min_width"
+ android:orientation="vertical"
+ android:elevation="@dimen/bubble_manage_menu_elevation"
+ android:paddingTop="@dimen/bubble_bar_manage_menu_padding_top"
+ android:paddingHorizontal="@dimen/bubble_bar_manage_menu_padding"
+ android:paddingBottom="@dimen/bubble_bar_manage_menu_padding"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/bubble_bar_manage_menu_bubble_section"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/bubble_bar_manage_menu_item_height"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingStart="14dp"
+ android:paddingEnd="12dp"
+ android:background="@drawable/bubble_manage_menu_section"
+ android:elevation="@dimen/bubble_manage_menu_elevation">
+
+ <ImageView
+ android:id="@+id/bubble_bar_manage_menu_bubble_icon"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
+ android:contentDescription="@null" />
+
+ <TextView
+ android:id="@+id/bubble_bar_manage_menu_bubble_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_weight="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault" />
+
+ <ImageView
+ android:id="@+id/bubble_bar_manage_menu_dismiss_icon"
+ android:layout_width="@dimen/bubble_bar_manage_menu_dismiss_icon_size"
+ android:layout_height="@dimen/bubble_bar_manage_menu_dismiss_icon_size"
+ android:layout_marginStart="8dp"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_expand_less"
+ app:tint="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/bubble_bar_manage_menu_actions_section"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="@dimen/bubble_bar_manage_menu_section_spacing"
+ android:background="@drawable/bubble_manage_menu_bg"
+ android:elevation="@dimen/bubble_manage_menu_elevation" />
+
+</com.android.wm.shell.bubbles.bar.BubbleBarMenuView>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 171a6b2..f2a0785 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -30,6 +30,9 @@
<color name="bubbles_light">#FFFFFF</color>
<color name="bubbles_dark">@color/GM2_grey_800</color>
<color name="bubbles_icon_tint">@color/GM2_grey_700</color>
+ <color name="bubble_bar_expanded_view_handle_light">#EBffffff</color>
+ <color name="bubble_bar_expanded_view_handle_dark">#99000000</color>
+ <color name="bubble_bar_expanded_view_menu_close">#DC362E</color>
<!-- PiP -->
<color name="pip_custom_close_bg">#D93025</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 2be34c9..2141259 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -229,7 +229,25 @@
<!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. -->
<dimen name="bubblebar_size">72dp</dimen>
<!-- The size of the drag handle / menu shown along with a bubble bar expanded view. -->
- <dimen name="bubblebar_expanded_view_menu_size">16dp</dimen>
+ <dimen name="bubble_bar_expanded_view_handle_size">40dp</dimen>
+ <!-- The width of the drag handle shown along with a bubble bar expanded view. -->
+ <dimen name="bubble_bar_expanded_view_handle_width">128dp</dimen>
+ <!-- The height of the drag handle shown along with a bubble bar expanded view. -->
+ <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>
+ <!-- Minimum width of the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_min_width">200dp</dimen>
+ <!-- Size of the dismiss icon in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_dismiss_icon_size">16dp</dimen>
+ <!-- Padding of the bubble bar manage menu, provides space for menu shadows -->
+ <dimen name="bubble_bar_manage_menu_padding">8dp</dimen>
+ <!-- Top padding of the bubble bar manage menu -->
+ <dimen name="bubble_bar_manage_menu_padding_top">2dp</dimen>
+ <!-- Spacing between sections of the bubble bar manage menu -->
+ <dimen name="bubble_bar_manage_menu_section_spacing">2dp</dimen>
+ <!-- Height of an item in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_item_height">52dp</dimen>
+ <!-- Size of the icons in the bubble bar manage menu. -->
+ <dimen name="bubble_bar_manage_menu_item_icon_size">20dp</dimen>
<!-- Bottom and end margin for compat buttons. -->
<dimen name="compat_button_margin">24dp</dimen>
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 102f2cb..504839f 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
@@ -855,7 +855,8 @@
return mIsAppBubble;
}
- Intent getSettingsIntent(final Context context) {
+ /** Creates open app settings intent */
+ public Intent getSettingsIntent(final Context context) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
final int uid = getUid(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 3eb9fa2..39338e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -720,6 +720,7 @@
// TODO(b/273312602): consider foldables where we do need a stack view when folded
if (mLayerView == null) {
mLayerView = new BubbleBarLayerView(mContext, this);
+ mLayerView.setUnBubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
}
} else {
if (mStackView == null) {
@@ -1221,6 +1222,13 @@
}
/**
+ * Dismiss bubble if it exists and remove it from the stack
+ */
+ public void dismissBubble(Bubble bubble, @Bubbles.DismissReason int reason) {
+ mBubbleData.dismissBubbleWithKey(bubble.getKey(), reason);
+ }
+
+ /**
* Performs a screenshot that may exclude the bubble layer, if one is present. The screenshot
* can be access via the supplied {@link ScreenshotSync#get()} asynchronously.
*/
@@ -1846,7 +1854,7 @@
if (mStackView != null) {
mStackView.setVisibility(VISIBLE);
}
- if (mLayerView != null && isStackExpanded()) {
+ if (mLayerView != null) {
mLayerView.setVisibility(VISIBLE);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 7a58159..da4a989 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.bubbles;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -110,6 +111,9 @@
try {
options.setTaskAlwaysOnTop(true);
options.setLaunchedFromBubble(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
Intent fillInIntent = new Intent();
// Apply flags to make behaviour match documentLaunchMode=always.
@@ -117,11 +121,19 @@
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
if (mBubble.isAppBubble()) {
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- mBubble.getAppBubbleIntent(),
- PendingIntent.FLAG_MUTABLE,
- null);
- mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
+ Context context =
+ mContext.createContextAsUser(
+ mBubble.getUser(), Context.CONTEXT_RESTRICTED);
+ PendingIntent pi = PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ mBubble.getAppBubbleIntent()
+ .addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
+ .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+ /* options= */ null);
+ mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
+ launchBounds);
} else if (mBubble.hasMetadataShortcutId()) {
options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 8ab9841..3a46797 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -192,6 +192,11 @@
}
info.rawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon;
+ float[] bubbleBitmapScale = new float[1];
+ info.bubbleBitmap = iconFactory.getBubbleBitmap(
+ iconFactory.getBubbleDrawable(c, info.shortcutInfo,
+ b.getIcon()), bubbleBitmapScale);
+
return info;
}
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 b8f049b..32ed102 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
@@ -16,11 +16,14 @@
package com.android.wm.shell.bubbles.bar;
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Outline;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
@@ -31,8 +34,12 @@
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.taskview.TaskView;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
/**
* Expanded view of a bubble when it's part of the bubble bar.
*
@@ -45,11 +52,14 @@
private BubbleController mController;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
+ private BubbleBarMenuViewController mMenuViewController;
+ private @Nullable Supplier<Rect> mLayerBoundsSupplier;
+ private @Nullable Consumer<String> mUnBubbleConversationCallback;
- private HandleView mMenuView;
- private TaskView mTaskView;
+ private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
+ private @Nullable TaskView mTaskView;
- private int mMenuHeight;
+ private int mHandleHeight;
private int mBackgroundColor;
private float mCornerRadius = 0f;
@@ -83,11 +93,9 @@
super.onFinishInflate();
Context context = getContext();
setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
- mMenuHeight = context.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_expanded_view_menu_size);
- mMenuView = new HandleView(context);
- addView(mMenuView);
-
+ mHandleHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_size);
+ addView(mHandleView);
applyThemeAttrs();
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@@ -98,6 +106,13 @@
});
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ // Hide manage menu when view disappears
+ mMenuViewController.hideMenu(false /* animated */);
+ }
+
/** Set the BubbleController on the view, must be called before doing anything else. */
public void initialize(BubbleController controller) {
mController = controller;
@@ -108,13 +123,43 @@
addView(mTaskView);
mTaskView.setEnableSurfaceClipping(true);
mTaskView.setCornerRadius(mCornerRadius);
+ mMenuViewController = new BubbleBarMenuViewController(mContext, this);
+ 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);
+ }
+
+ @Override
+ public void onUnBubbleConversation(Bubble bubble) {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubble.getKey());
+ }
+ }
+
+ @Override
+ public void onOpenAppSettings(Bubble bubble) {
+ mController.collapseStack();
+ mContext.startActivityAsUser(bubble.getSettingsIntent(mContext), bubble.getUser());
+ }
+
+ @Override
+ public void onDismissBubble(Bubble bubble) {
+ mController.dismissBubble(bubble, Bubbles.DISMISS_USER_REMOVED);
+ }
+ });
+ mHandleView.setOnClickListener(view -> {
+ mMenuViewController.showMenu(true /* animated */);
+ });
}
// TODO (b/275087636): call this when theme/config changes
void applyThemeAttrs() {
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources());
- final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
@@ -123,14 +168,12 @@
ta.recycle();
- mMenuView.setCornerRadius(mCornerRadius);
- mMenuHeight = getResources().getDimensionPixelSize(
- R.dimen.bubblebar_expanded_view_menu_size);
+ mHandleHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_size);
if (mTaskView != null) {
mTaskView.setCornerRadius(mCornerRadius);
- mTaskView.setElevation(150);
- updateMenuColor();
+ updateHandleAndBackgroundColor(true /* animated */);
}
}
@@ -138,10 +181,8 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
-
- // Add corner radius here so that the menu extends behind the rounded corners of TaskView.
- int menuViewHeight = Math.min((int) (mMenuHeight + mCornerRadius), height);
- measureChild(mMenuView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
+ int menuViewHeight = Math.min(mHandleHeight, height);
+ measureChild(mHandleView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
MeasureSpec.getMode(heightMeasureSpec)));
if (mTaskView != null) {
@@ -153,12 +194,12 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
// Drag handle above
- final int dragHandleBottom = t + mMenuView.getMeasuredHeight();
- mMenuView.layout(l, t, r, dragHandleBottom);
+ final int dragHandleBottom = t + mHandleView.getMeasuredHeight();
+ mHandleView.layout(l, t, r, dragHandleBottom);
if (mTaskView != null) {
- // Subtract radius so that the menu extends behind the rounded corners of TaskView.
- mTaskView.layout(l, (int) (dragHandleBottom - mCornerRadius), r,
+ mTaskView.layout(l, dragHandleBottom, r,
dragHandleBottom + mTaskView.getMeasuredHeight());
}
}
@@ -166,7 +207,7 @@
@Override
public void onTaskCreated() {
setContentVisibility(true);
- updateMenuColor();
+ updateHandleAndBackgroundColor(false /* animated */);
}
@Override
@@ -187,11 +228,13 @@
}
mBubbleTaskViewHelper.cleanUpTaskView();
}
+ mMenuViewController.hideMenu(false /* animated */);
}
- /** Updates the bubble shown in this task view. */
+ /** Updates the bubble shown in the expanded view. */
public void update(Bubble bubble) {
mBubbleTaskViewHelper.update(bubble);
+ mMenuViewController.updateMenu(bubble);
}
/** The task id of the activity shown in the task view, if it exists. */
@@ -199,6 +242,17 @@
return mBubbleTaskViewHelper != null ? mBubbleTaskViewHelper.getTaskId() : INVALID_TASK_ID;
}
+ /** Sets layer bounds supplier used for obscured touchable region of task view */
+ void setLayerBoundsSupplier(@Nullable Supplier<Rect> supplier) {
+ mLayerBoundsSupplier = supplier;
+ }
+
+ /** Sets the function to call to un-bubble the given conversation. */
+ public void setUnBubbleConversationCallback(
+ @Nullable Consumer<String> unBubbleConversationCallback) {
+ mUnBubbleConversationCallback = unBubbleConversationCallback;
+ }
+
/**
* Call when the location or size of the view has changed to update TaskView.
*/
@@ -218,16 +272,33 @@
}
}
- /** Updates the menu bar to be the status bar color specified by the app. */
- private void updateMenuColor() {
+ /**
+ * Updates the background color to match with task view status/bg color, and sets handle color
+ * to contrast with the background
+ */
+ private void updateHandleAndBackgroundColor(boolean animated) {
if (mTaskView == null) return;
- ActivityManager.RunningTaskInfo info = mTaskView.getTaskInfo();
- final int taskBgColor = info.taskDescription.getStatusBarColor();
- final int color = Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
- if (color != -1) {
- mMenuView.setBackgroundColor(color);
+ final int color = getTaskViewColor();
+ final boolean isRegionDark = Color.luminance(color) <= 0.5;
+ mHandleView.updateHandleColor(isRegionDark, animated);
+ setBackgroundColor(color);
+ }
+
+ /**
+ * Retrieves task view status/nav bar color or background if available
+ *
+ * TODO (b/283075226): Update with color sampling when
+ * RegionSamplingHelper or alternative is available
+ */
+ private @ColorInt int getTaskViewColor() {
+ if (mTaskView == null || mTaskView.getTaskInfo() == null) return mBackgroundColor;
+ ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
+ if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
+ return taskDescription.getStatusBarColor();
+ } else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
+ return taskDescription.getBackgroundColor();
} else {
- mMenuView.setBackgroundColor(mBackgroundColor);
+ return mBackgroundColor;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
new file mode 100644
index 0000000..ce26bc0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -0,0 +1,114 @@
+/*
+ * 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import androidx.annotation.ColorInt;
+import androidx.core.content.ContextCompat;
+
+import com.android.wm.shell.R;
+
+/**
+ * Handle view to show at the top of a bubble bar expanded view.
+ */
+public class BubbleBarHandleView extends View {
+ private static final long COLOR_CHANGE_DURATION = 120;
+
+ private int mHandleWidth;
+ private int mHandleHeight;
+ private @ColorInt int mHandleLightColor;
+ private @ColorInt int mHandleDarkColor;
+ private @Nullable ObjectAnimator mColorChangeAnim;
+
+ public BubbleBarHandleView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mHandleWidth = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_width);
+ mHandleHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_height);
+ mHandleLightColor = ContextCompat.getColor(getContext(),
+ R.color.bubble_bar_expanded_view_handle_light);
+ mHandleDarkColor = ContextCompat.getColor(getContext(),
+ R.color.bubble_bar_expanded_view_handle_dark);
+
+ setClipToOutline(true);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int handleCenterX = view.getWidth() / 2;
+ final int handleCenterY = view.getHeight() / 2;
+ final float handleRadius = mHandleHeight / 2f;
+ Rect handleBounds = new Rect(
+ handleCenterX - mHandleWidth / 2,
+ handleCenterY - mHandleHeight / 2,
+ handleCenterX + mHandleWidth / 2,
+ handleCenterY + mHandleHeight / 2);
+ outline.setRoundRect(handleBounds, handleRadius);
+ }
+ });
+ }
+
+ /**
+ * Updates the handle color.
+ *
+ * @param isRegionDark Whether the background behind the handle is dark, and thus the handle
+ * should be light (and vice versa).
+ * @param animated Whether to animate the change, or apply it immediately.
+ */
+ public void updateHandleColor(boolean isRegionDark, boolean animated) {
+ int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
+ if (mColorChangeAnim != null) {
+ mColorChangeAnim.cancel();
+ }
+ if (animated) {
+ mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
+ mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mColorChangeAnim = null;
+ }
+ });
+ mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
+ mColorChangeAnim.start();
+ } else {
+ setBackgroundColor(newColor);
+ }
+ }
+}
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 b1a725b..bc622e7 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
@@ -32,6 +32,8 @@
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
+import java.util.function.Consumer;
+
/**
* Similar to {@link com.android.wm.shell.bubbles.BubbleStackView}, this view is added to window
* manager to display bubbles. However, it is only used when bubbles are being displayed in
@@ -53,6 +55,7 @@
@Nullable
private BubbleViewProvider mExpandedBubble;
private BubbleBarExpandedView mExpandedView;
+ private @Nullable Consumer<String> mUnBubbleConversationCallback;
// TODO(b/273310265) - currently the view is always on the right, need to update for RTL.
/** Whether the expanded view is displaying on the left of the screen or not. */
@@ -146,6 +149,13 @@
final int width = mPositioner.getExpandedViewWidthForBubbleBar();
final int height = mPositioner.getExpandedViewHeightForBubbleBar();
mExpandedView.setVisibility(GONE);
+ mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
+ mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
+ mExpandedView.setUnBubbleConversationCallback(bubbleKey -> {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubbleKey);
+ }
+ });
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
@@ -165,6 +175,12 @@
showScrim(false);
}
+ /** Sets the function to call to un-bubble the given conversation. */
+ public void setUnBubbleConversationCallback(
+ @Nullable Consumer<String> unBubbleConversationCallback) {
+ mUnBubbleConversationCallback = unBubbleConversationCallback;
+ }
+
/** 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/BubbleBarMenuItemView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java
new file mode 100644
index 0000000..00b9777
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java
@@ -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.wm.shell.bubbles.bar;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Bubble bar expanded view menu item view to display menu action details
+ */
+public class BubbleBarMenuItemView extends LinearLayout {
+ private ImageView mImageView;
+ private TextView mTextView;
+
+ public BubbleBarMenuItemView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarMenuItemView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mImageView = findViewById(R.id.bubble_bar_menu_item_icon);
+ mTextView = findViewById(R.id.bubble_bar_menu_item_title);
+ }
+
+ /**
+ * Update menu item with the details and tint color
+ */
+ void update(Icon icon, String title, @ColorInt int tint) {
+ if (tint == Color.TRANSPARENT) {
+ final TypedArray typedArray = getContext().obtainStyledAttributes(
+ new int[]{android.R.attr.textColorPrimary});
+ mTextView.setTextColor(typedArray.getColor(0, Color.BLACK));
+ } else {
+ icon.setTint(tint);
+ mTextView.setTextColor(tint);
+ }
+
+ mImageView.setImageIcon(icon);
+ mTextView.setText(title);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
new file mode 100644
index 0000000..211fe0d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles.bar;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.Bubble;
+
+import java.util.ArrayList;
+
+/**
+ * Bubble bar expanded view menu
+ */
+public class BubbleBarMenuView extends LinearLayout {
+ private ViewGroup mBubbleSectionView;
+ private ViewGroup mActionsSectionView;
+ private ImageView mBubbleIconView;
+ private TextView mBubbleTitleView;
+
+ public BubbleBarMenuView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ }
+
+ public BubbleBarMenuView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBubbleSectionView = findViewById(R.id.bubble_bar_manage_menu_bubble_section);
+ mActionsSectionView = findViewById(R.id.bubble_bar_manage_menu_actions_section);
+ mBubbleIconView = findViewById(R.id.bubble_bar_manage_menu_bubble_icon);
+ mBubbleTitleView = findViewById(R.id.bubble_bar_manage_menu_bubble_title);
+ }
+
+ /** Update menu details with bubble info */
+ void updateInfo(Bubble bubble) {
+ if (bubble.getIcon() != null) {
+ mBubbleIconView.setImageIcon(bubble.getIcon());
+ } else {
+ mBubbleIconView.setImageBitmap(bubble.getBubbleIcon());
+ }
+ mBubbleTitleView.setText(bubble.getTitle());
+ }
+
+ /**
+ * Update menu action items views
+ * @param actions used to populate menu item views
+ */
+ void updateActions(ArrayList<MenuAction> actions) {
+ mActionsSectionView.removeAllViews();
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+
+ for (MenuAction action : actions) {
+ BubbleBarMenuItemView itemView = (BubbleBarMenuItemView) inflater.inflate(
+ R.layout.bubble_bar_menu_item, mActionsSectionView, false);
+ itemView.update(action.mIcon, action.mTitle, action.mTint);
+ itemView.setOnClickListener(action.mOnClick);
+ mActionsSectionView.addView(itemView);
+ }
+ }
+
+ /** Sets on close menu listener */
+ void setOnCloseListener(Runnable onClose) {
+ mBubbleSectionView.setOnClickListener(view -> {
+ onClose.run();
+ });
+ }
+
+ /**
+ * Overridden to proxy to section views alpha.
+ * @implNote
+ * If animate alpha on the parent (menu container) view, section view shadows get distorted.
+ * To prevent distortion and artifacts alpha changes applied directly on the section views.
+ */
+ @Override
+ public void setAlpha(float alpha) {
+ mBubbleSectionView.setAlpha(alpha);
+ mActionsSectionView.setAlpha(alpha);
+ }
+
+ /**
+ * Overridden to proxy section view alpha value.
+ * @implNote
+ * The assumption is that both section views have the same alpha value
+ */
+ @Override
+ public float getAlpha() {
+ return mBubbleSectionView.getAlpha();
+ }
+
+ /**
+ * Menu action details used to create menu items
+ */
+ static class MenuAction {
+ private Icon mIcon;
+ private @ColorInt int mTint;
+ private String mTitle;
+ private OnClickListener mOnClick;
+
+ MenuAction(Icon icon, String title, OnClickListener onClick) {
+ this(icon, title, Color.TRANSPARENT, onClick);
+ }
+
+ MenuAction(Icon icon, String title, @ColorInt int tint, OnClickListener onClick) {
+ this.mIcon = icon;
+ this.mTitle = title;
+ this.mTint = tint;
+ this.mOnClick = onClick;
+ }
+ }
+}
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
new file mode 100644
index 0000000..8be140c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -0,0 +1,242 @@
+/*
+ * 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.core.content.ContextCompat;
+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.Bubble;
+
+import java.util.ArrayList;
+
+/**
+ * Manages bubble bar expanded view menu presentation and animations
+ */
+class BubbleBarMenuViewController {
+ private static final float MENU_INITIAL_SCALE = 0.5f;
+ private final Context mContext;
+ private final ViewGroup mRootView;
+ private @Nullable Listener mListener;
+ private @Nullable Bubble mBubble;
+ private @Nullable BubbleBarMenuView mMenuView;
+ /** A transparent view used to intercept touches to collapse menu when presented */
+ private @Nullable View mScrimView;
+ private @Nullable PhysicsAnimator<BubbleBarMenuView> mMenuAnimator;
+ private PhysicsAnimator.SpringConfig mMenuSpringConfig;
+
+ BubbleBarMenuViewController(Context context, ViewGroup rootView) {
+ mContext = context;
+ mRootView = rootView;
+ mMenuSpringConfig = new PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ }
+
+ /** Sets menu actions listener */
+ void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ /** Update menu with bubble */
+ void updateMenu(@NonNull Bubble bubble) {
+ mBubble = bubble;
+ }
+
+ /**
+ * Show bubble bar expanded view menu
+ * @param animated if should animate transition
+ */
+ void showMenu(boolean animated) {
+ if (mMenuView == null || mScrimView == null) {
+ setupMenu();
+ }
+ cancelAnimations();
+ mMenuView.setVisibility(View.VISIBLE);
+ mScrimView.setVisibility(View.VISIBLE);
+ Runnable endActions = () -> {
+ mMenuView.getChildAt(0).requestAccessibilityFocus();
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(true /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(true /* show */, endActions);
+ } else {
+ endActions.run();
+ }
+ }
+
+ /**
+ * Hide bubble bar expanded view menu
+ * @param animated if should animate transition
+ */
+ void hideMenu(boolean animated) {
+ if (mMenuView == null || mScrimView == null) return;
+ cancelAnimations();
+ Runnable endActions = () -> {
+ mMenuView.setVisibility(View.GONE);
+ mScrimView.setVisibility(View.GONE);
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(false /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(false /* show */, endActions);
+ } else {
+ endActions.run();
+ }
+ }
+
+ /**
+ * Animate show/hide menu transition
+ * @param show if should show or hide the menu
+ * @param endActions will be called when animation ends
+ */
+ private void animateTransition(boolean show, Runnable endActions) {
+ if (mMenuView == null) return;
+ mMenuAnimator = PhysicsAnimator.getInstance(mMenuView);
+ mMenuAnimator.setDefaultSpringConfig(mMenuSpringConfig);
+ mMenuAnimator
+ .spring(DynamicAnimation.ALPHA, show ? 1f : 0f)
+ .spring(DynamicAnimation.SCALE_Y, show ? 1f : MENU_INITIAL_SCALE)
+ .withEndActions(() -> {
+ mMenuAnimator = null;
+ endActions.run();
+ })
+ .start();
+ }
+
+ /** Cancel running animations */
+ private void cancelAnimations() {
+ if (mMenuAnimator != null) {
+ mMenuAnimator.cancel();
+ mMenuAnimator = null;
+ }
+ }
+
+ /** Sets up and inflate menu views */
+ private void setupMenu() {
+ // Menu view setup
+ mMenuView = (BubbleBarMenuView) LayoutInflater.from(mContext).inflate(
+ R.layout.bubble_bar_menu_view, mRootView, false);
+ mMenuView.setAlpha(0f);
+ mMenuView.setPivotY(0f);
+ mMenuView.setScaleY(MENU_INITIAL_SCALE);
+ mMenuView.setOnCloseListener(() -> hideMenu(true /* animated */));
+ if (mBubble != null) {
+ mMenuView.updateInfo(mBubble);
+ mMenuView.updateActions(createMenuActions(mBubble));
+ }
+ // Scrim view setup
+ mScrimView = new View(mContext);
+ mScrimView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mScrimView.setOnClickListener(view -> hideMenu(true /* animated */));
+ // Attach to root view
+ mRootView.addView(mScrimView);
+ mRootView.addView(mMenuView);
+ }
+
+ /**
+ * Creates menu actions to populate menu view
+ * @param bubble used to create actions depending on bubble type
+ */
+ private ArrayList<BubbleBarMenuView.MenuAction> createMenuActions(Bubble bubble) {
+ ArrayList<BubbleBarMenuView.MenuAction> menuActions = new ArrayList<>();
+ Resources resources = mContext.getResources();
+
+ if (bubble.isConversation()) {
+ // Don't bubble conversation action
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ Icon.createWithResource(mContext, R.drawable.bubble_ic_stop_bubble),
+ resources.getString(R.string.bubbles_dont_bubble_conversation),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onUnBubbleConversation(bubble);
+ }
+ }
+ ));
+ // Open settings action
+ Icon appIcon = bubble.getRawAppBadge() != null ? Icon.createWithBitmap(
+ bubble.getRawAppBadge()) : null;
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ appIcon,
+ resources.getString(R.string.bubbles_app_settings, bubble.getAppName()),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onOpenAppSettings(bubble);
+ }
+ }
+ ));
+ }
+
+ // Dismiss bubble action
+ menuActions.add(new BubbleBarMenuView.MenuAction(
+ Icon.createWithResource(resources, R.drawable.ic_remove_no_shadow),
+ resources.getString(R.string.bubble_dismiss_text),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_menu_close),
+ view -> {
+ hideMenu(true /* animated */);
+ if (mListener != null) {
+ mListener.onDismissBubble(bubble);
+ }
+ }
+ ));
+
+ return menuActions;
+ }
+
+ /**
+ * Bubble bar expanded view menu actions listener
+ */
+ interface Listener {
+ /**
+ * Called when manage menu is shown/hidden
+ * If animated will be called when animation ends
+ */
+ void onMenuVisibilityChanged(boolean visible);
+
+ /**
+ * Un-bubbles conversation and removes the bubble from the stack
+ * This conversation will not be bubbled with new messages
+ * @see com.android.wm.shell.bubbles.BubbleController
+ */
+ void onUnBubbleConversation(Bubble bubble);
+
+ /**
+ * Launches app notification bubble settings for the bubble with intent created in:
+ * {@code Bubble.getSettingsIntent}
+ */
+ void onOpenAppSettings(Bubble bubble);
+
+ /**
+ * Dismiss bubble and remove it from the bubble stack
+ */
+ void onDismissBubble(Bubble bubble);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java
deleted file mode 100644
index 9ee8a9d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/HandleView.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.Gravity;
-import android.widget.LinearLayout;
-
-/**
- * Handle / menu view to show at the top of a bubble bar expanded view.
- */
-public class HandleView extends LinearLayout {
-
- // TODO(b/273307221): implement the manage menu in this view.
- public HandleView(Context context) {
- super(context);
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.CENTER);
- }
-
- /**
- * The menu extends past the top of the TaskView because of the rounded corners. This means
- * to center content in the menu we must subtract the radius (i.e. the amount of space covered
- * by TaskView).
- */
- public void setCornerRadius(float radius) {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), (int) radius);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index c76937d..ec26800 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -76,6 +76,9 @@
private int mCurrentHeight;
private AnimatorSet mAnimator;
private boolean mTouching;
+ private boolean mHovering;
+ private final int mHoveringWidth;
+ private final int mHoveringHeight;
public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -87,6 +90,8 @@
mCurrentHeight = mHeight;
mTouchingWidth = mWidth > mHeight ? mWidth / 2 : mWidth;
mTouchingHeight = mHeight > mWidth ? mHeight / 2 : mHeight;
+ mHoveringWidth = mWidth > mHeight ? ((int) (mWidth * 1.5f)) : mWidth;
+ mHoveringHeight = mHeight > mWidth ? ((int) (mHeight * 1.5f)) : mHeight;
}
/** Sets touching state for this handle view. */
@@ -94,24 +99,32 @@
if (touching == mTouching) {
return;
}
+ setInputState(touching, animate, mTouchingWidth, mTouchingHeight);
+ mTouching = touching;
+ }
+
+ /** Sets hovering state for this handle view. */
+ public void setHovering(boolean hovering, boolean animate) {
+ if (hovering == mHovering) {
+ return;
+ }
+ setInputState(hovering, animate, mHoveringWidth, mHoveringHeight);
+ mHovering = hovering;
+ }
+
+ private void setInputState(boolean stateOn, boolean animate, int stateWidth, int stateHeight) {
if (mAnimator != null) {
mAnimator.cancel();
mAnimator = null;
}
if (!animate) {
- if (touching) {
- mCurrentWidth = mTouchingWidth;
- mCurrentHeight = mTouchingHeight;
- } else {
- mCurrentWidth = mWidth;
- mCurrentHeight = mHeight;
- }
+ mCurrentWidth = stateOn ? stateWidth : mWidth;
+ mCurrentHeight = stateOn ? stateHeight : mHeight;
invalidate();
} else {
- animateToTarget(touching ? mTouchingWidth : mWidth,
- touching ? mTouchingHeight : mHeight, touching);
+ animateToTarget(stateOn ? stateWidth : mWidth,
+ stateOn ? stateHeight : mHeight, stateOn);
}
- mTouching = touching;
}
private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 69f0bad..262d487 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -17,14 +17,19 @@
package com.android.wm.shell.common.split;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
+import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CURSOR_HOVER_STATES_ENABLED;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
+import android.provider.DeviceConfig;
import android.util.AttributeSet;
import android.util.Property;
import android.view.GestureDetector;
@@ -32,6 +37,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.SurfaceControlViewHost;
import android.view.VelocityTracker;
import android.view.View;
@@ -46,6 +52,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -222,7 +229,7 @@
for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = insetsState.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
mTempRect.inset(source.calculateVisibleInsets(mTempRect));
}
}
@@ -270,6 +277,12 @@
}
@Override
+ public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+ return PointerIcon.getSystemIcon(getContext(),
+ isLandscape() ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW);
+ }
+
+ @Override
public boolean onTouch(View v, MotionEvent event) {
if (mSplitLayout == null || !mInteractive) {
return false;
@@ -371,6 +384,43 @@
mViewHost.relayout(lp);
}
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ /* defaultValue = */ false)) {
+ return false;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
+ setHovering();
+ return true;
+ } else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
+ releaseHovering();
+ return true;
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ void setHovering() {
+ mHandle.setHovering(true, true);
+ mHandle.animate()
+ .setInterpolator(Interpolators.TOUCH_RESPONSE)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
+ }
+
+ @VisibleForTesting
+ void releaseHovering() {
+ mHandle.setHovering(false, true);
+ mHandle.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+ .translationZ(0)
+ .start();
+ }
+
/**
* Set divider should interactive to user or not.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 4980e49..2dbccac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -47,6 +47,7 @@
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopModeController;
@@ -264,8 +265,13 @@
static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
ShellInit shellInit,
Transitions transitions,
- WindowDecorViewModel windowDecorViewModel) {
- return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
+ Context context,
+ WindowDecorViewModel windowDecorViewModel,
+ DisplayController displayController,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellAnimationThread ShellExecutor animExecutor) {
+ return new FreeformTaskTransitionHandler(shellInit, transitions, context,
+ windowDecorViewModel, displayController, mainExecutor, animExecutor);
}
@WMSingleton
@@ -536,9 +542,12 @@
Optional<PipTouchHandler> pipTouchHandlerOptional,
Optional<RecentsTransitionHandler> recentsTransitionHandler,
KeyguardTransitionHandler keyguardTransitionHandler,
+ Optional<DesktopModeController> desktopModeController,
+ Optional<DesktopTasksController> desktopTasksController,
Transitions transitions) {
return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
- pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler);
+ pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler,
+ desktopModeController, desktopTasksController);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index b9d2be2..db6c258 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -33,6 +33,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Region;
import android.net.Uri;
@@ -414,6 +415,25 @@
}
/**
+ * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
+ * This is intended to be used when desktop mode is part of another animation but isn't, itself,
+ * animating.
+ */
+ public void syncSurfaceState(@NonNull TransitionInfo info,
+ SurfaceControl.Transaction finishTransaction) {
+ // Add rounded corners to freeform windows
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{android.R.attr.dialogCornerRadius});
+ final int cornerRadius = ta.getDimensionPixelSize(0, 0);
+ ta.recycle();
+ for (TransitionInfo.Change change: info.getChanges()) {
+ if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ finishTransaction.setCornerRadius(change.getLeash(), cornerRadius);
+ }
+ }
+ }
+
+ /**
* A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
*/
private final class SettingsObserver extends ContentObserver {
@@ -500,6 +520,11 @@
}
@Override
+ public void showDesktopApp(int taskId) throws RemoteException {
+ // TODO
+ }
+
+ @Override
public int getVisibleTaskCount(int displayId) throws RemoteException {
int[] result = new int[1];
executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
@@ -508,5 +533,20 @@
);
return result[0];
}
+
+ @Override
+ public void stashDesktopApps(int displayId) throws RemoteException {
+ // Stashing of desktop apps not needed. Apps always launch on desktop
+ }
+
+ @Override
+ public void hideStashedDesktopApps(int displayId) throws RemoteException {
+ // Stashing of desktop apps not needed. Apps always launch on desktop
+ }
+
+ @Override
+ public void setTaskListener(IDesktopTaskListener listener) throws RemoteException {
+ // TODO(b/261234402): move visibility from sysui state to listener
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 3ab175d..402bb96 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -43,6 +43,7 @@
*/
val activeTasks: ArraySet<Int> = ArraySet(),
val visibleTasks: ArraySet<Int> = ArraySet(),
+ var stashed: Boolean = false
)
// Tasks currently in freeform mode, ordered from top to bottom (top is at index 0).
@@ -312,6 +313,33 @@
}
/**
+ * Update stashed status on display with id [displayId]
+ */
+ fun setStashed(displayId: Int, stashed: Boolean) {
+ val data = displayData.getOrCreate(displayId)
+ val oldValue = data.stashed
+ data.stashed = stashed
+ if (oldValue != stashed) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: mark stashed=%b displayId=%d",
+ stashed,
+ displayId
+ )
+ visibleTasksListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onStashedChanged(displayId, stashed) }
+ }
+ }
+ }
+
+ /**
+ * Check if display with id [displayId] has desktop tasks stashed
+ */
+ fun isStashed(displayId: Int): Boolean {
+ return displayData[displayId]?.stashed ?: false
+ }
+
+ /**
* Defines interface for classes that can listen to changes for active tasks in desktop mode.
*/
interface ActiveTasksListener {
@@ -331,5 +359,11 @@
*/
@JvmDefault
fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {}
+
+ /**
+ * Called when the desktop stashed status changes.
+ */
+ @JvmDefault
+ fun onStashedChanged(displayId: Int, stashed: Boolean) {}
}
}
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 91bb155..d191fcd 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
@@ -16,6 +16,7 @@
package com.android.wm.shell.desktopmode
+import android.R
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -24,6 +25,7 @@
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
+import android.content.res.TypedArray
import android.graphics.Point
import android.graphics.Rect
import android.graphics.Region
@@ -46,6 +48,7 @@
import com.android.wm.shell.common.ExternalInterfaceBinder
import com.android.wm.shell.common.RemoteCallable
import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SingleInstanceRemoteListener
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.annotations.ExternalThread
import com.android.wm.shell.common.annotations.ShellMainThread
@@ -118,6 +121,30 @@
}
}
+ /**
+ * Stash desktop tasks on display with id [displayId].
+ *
+ * When desktop tasks are stashed, launcher home screen icons are fully visible. New apps
+ * launched in this state will be added to the desktop. Existing desktop tasks will be brought
+ * back to front during the launch.
+ */
+ fun stashDesktopApps(displayId: Int) {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: stashDesktopApps")
+ desktopModeTaskRepository.setStashed(displayId, true)
+ }
+
+ /**
+ * Clear the stashed state for the given display
+ */
+ fun hideStashedDesktopApps(displayId: Int) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: hideStashedApps displayId=%d",
+ displayId
+ )
+ desktopModeTaskRepository.setStashed(displayId, false)
+ }
+
/** Get number of tasks that are marked as visible */
fun getVisibleTaskCount(displayId: Int): Int {
return desktopModeTaskRepository.getVisibleTaskCount(displayId)
@@ -252,6 +279,11 @@
}
/** Move a task to the front */
+ fun moveTaskToFront(taskId: Int) {
+ shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveTaskToFront(task) }
+ }
+
+ /** Move a task to the front */
fun moveTaskToFront(taskInfo: RunningTaskInfo) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
@@ -397,6 +429,11 @@
transition: IBinder,
request: TransitionRequestInfo
): WindowContainerTransaction? {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: handleRequest request=%s",
+ request
+ )
// Check if we should skip handling this transition
val shouldHandleRequest =
when {
@@ -418,43 +455,82 @@
}
val task: RunningTaskInfo = request.triggerTask
- val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
- // Check if we should switch a fullscreen task to freeform
- if (task.windowingMode == WINDOWING_MODE_FULLSCREEN) {
- // If there are any visible desktop tasks, switch the task to freeform
- if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
- KtProtoLog.d(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: switch fullscreen task to freeform on transition" +
- " taskId=%d",
- task.taskId
- )
- return WindowContainerTransaction().also { wct ->
- addMoveToDesktopChanges(wct, task.token)
- }
- }
+ return when {
+ // If display has tasks stashed, handle as stashed launch
+ desktopModeTaskRepository.isStashed(task.displayId) -> handleStashedTaskLaunch(task)
+ // Check if fullscreen task should be updated
+ task.windowingMode == WINDOWING_MODE_FULLSCREEN -> handleFullscreenTaskLaunch(task)
+ // Check if freeform task should be updated
+ task.windowingMode == WINDOWING_MODE_FREEFORM -> handleFreeformTaskLaunch(task)
+ else -> null
}
+ }
- // CHeck if we should switch a freeform task to fullscreen
- if (task.windowingMode == WINDOWING_MODE_FREEFORM) {
- // If no visible desktop tasks, switch this task to freeform as the transition came
- // outside of this controller
- if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
- KtProtoLog.d(
+ /**
+ * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
+ * This is intended to be used when desktop mode is part of another animation but isn't, itself,
+ * animating.
+ */
+ fun syncSurfaceState(
+ info: TransitionInfo,
+ finishTransaction: SurfaceControl.Transaction
+ ) {
+ // Add rounded corners to freeform windows
+ val ta: TypedArray = context.obtainStyledAttributes(
+ intArrayOf(R.attr.dialogCornerRadius))
+ val cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat()
+ ta.recycle()
+ info.changes
+ .filter { it.taskInfo.windowingMode == WINDOWING_MODE_FREEFORM }
+ .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
+ }
+
+ private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
+ if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
+ KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: switch freeform task to fullscreen oon transition" +
- " taskId=%d",
+ " taskId=%d",
task.taskId
- )
- return WindowContainerTransaction().also { wct ->
- addMoveToFullscreenChanges(wct, task.token)
- }
+ )
+ return WindowContainerTransaction().also { wct ->
+ addMoveToFullscreenChanges(wct, task.token)
}
}
return null
}
+ private fun handleFullscreenTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
+ if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: switch fullscreen task to freeform on transition" +
+ " taskId=%d",
+ task.taskId
+ )
+ return WindowContainerTransaction().also { wct ->
+ addMoveToDesktopChanges(wct, task.token)
+ }
+ }
+ return null
+ }
+
+ private fun handleStashedTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: launch apps with stashed on transition taskId=%d",
+ task.taskId
+ )
+ val wct = WindowContainerTransaction()
+ bringDesktopAppsToFront(task.displayId, wct)
+ addMoveToDesktopChanges(wct, task.token)
+ desktopModeTaskRepository.setStashed(task.displayId, false)
+ return wct
+ }
+
private fun addMoveToDesktopChanges(
wct: WindowContainerTransaction,
token: WindowContainerToken
@@ -524,14 +600,16 @@
* Perform checks required on drag end. Move to fullscreen if drag ends in status bar area.
*
* @param taskInfo the task being dragged.
- * @param position position of surface when drag ends
+ * @param position position of surface when drag ends.
+ * @param y the Y position of the motion event.
*/
fun onDragPositioningEnd(
taskInfo: RunningTaskInfo,
- position: Point
+ position: Point,
+ y: Float
) {
val statusBarHeight = getStatusBarHeight(taskInfo)
- if (position.y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
moveToFullscreenWithAnimation(taskInfo, position)
}
}
@@ -658,8 +736,46 @@
@BinderThread
private class IDesktopModeImpl(private var controller: DesktopTasksController?) :
IDesktopMode.Stub(), ExternalInterfaceBinder {
+
+ private lateinit var remoteListener:
+ SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>
+
+ private val listener: VisibleTasksListener = object : VisibleTasksListener {
+ override fun onVisibilityChanged(displayId: Int, visible: Boolean) {
+ // TODO(b/261234402): move visibility from sysui state to listener
+ remoteListener.call { l -> l.onVisibilityChanged(displayId, visible) }
+ }
+
+ override fun onStashedChanged(displayId: Int, stashed: Boolean) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onStashedChanged stashed=%b display=%d",
+ stashed,
+ displayId
+ )
+ remoteListener.call { l -> l.onStashedChanged(displayId, stashed) }
+ }
+ }
+
+ init {
+ remoteListener =
+ SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>(
+ controller,
+ { c ->
+ c.desktopModeTaskRepository.addVisibleTasksListener(
+ listener,
+ c.mainExecutor
+ )
+ },
+ { c ->
+ c.desktopModeTaskRepository.removeVisibleTasksListener(listener)
+ }
+ )
+ }
+
/** Invalidates this instance, preventing future calls from updating the controller. */
override fun invalidate() {
+ remoteListener.unregister()
controller = null
}
@@ -670,6 +786,27 @@
) { c -> c.showDesktopApps(displayId) }
}
+ override fun stashDesktopApps(displayId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "stashDesktopApps"
+ ) { c -> c.stashDesktopApps(displayId) }
+ }
+
+ override fun hideStashedDesktopApps(displayId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "hideStashedDesktopApps"
+ ) { c -> c.hideStashedDesktopApps(displayId) }
+ }
+
+ override fun showDesktopApp(taskId: Int) {
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "showDesktopApp"
+ ) { c -> c.moveTaskToFront(taskId) }
+ }
+
override fun getVisibleTaskCount(displayId: Int): Int {
val result = IntArray(1)
ExecutorUtils.executeRemoteCallWithTaskPermission(
@@ -680,6 +817,18 @@
)
return result[0]
}
+
+ override fun setTaskListener(listener: IDesktopTaskListener?) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: set task listener=%s",
+ listener ?: "null"
+ )
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "setTaskListener"
+ ) { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() }
+ }
}
companion object {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 899d672..ee3a080 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -16,6 +16,8 @@
package com.android.wm.shell.desktopmode;
+import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+
/**
* Interface that is exposed to remote callers to manipulate desktop mode features.
*/
@@ -24,6 +26,18 @@
/** Show apps on the desktop on the given display */
void showDesktopApps(int displayId);
+ /** Stash apps on the desktop to allow launching another app from home screen */
+ void stashDesktopApps(int displayId);
+
+ /** Hide apps that may be stashed */
+ void hideStashedDesktopApps(int displayId);
+
+ /** Bring task with the given id to front */
+ oneway void showDesktopApp(int taskId);
+
/** Get count of visible desktop tasks on the given display */
int getVisibleTaskCount(int displayId);
+
+ /** Set listener that will receive callbacks about updates to desktop tasks */
+ oneway void setTaskListener(IDesktopTaskListener listener);
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
new file mode 100644
index 0000000..39128a8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.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 com.android.wm.shell.desktopmode;
+
+/**
+ * Allows external processes to register a listener in WMShell to get updates about desktop task
+ * state.
+ */
+interface IDesktopTaskListener {
+
+ /** Desktop task visibility has change. Visible if at least 1 task is visible. */
+ oneway void onVisibilityChanged(int displayId, boolean visible);
+
+ /** Desktop task stashed status has changed. */
+ oneway void onStashedChanged(int displayId, boolean stashed);
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
index 99922fb..c795a05 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -26,6 +26,12 @@
- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
traces in Winscope)
+### Kotlin
+
+Protolog tool does not yet have support for Kotlin code (see [b/168581922](https://b.corp.google.com/issues/168581922)).
+For logging in Kotlin, use the [KtProtoLog](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt)
+class which has a similar API to the Java ProtoLog class.
+
### Enabling ProtoLog command line logging
Run these commands to enable protologs for both WM Core and WM Shell to print to logcat.
```shell
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index 04fc79a..55e34fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -19,9 +19,15 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
+import android.util.ArrayMap;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -31,6 +37,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -39,23 +47,37 @@
import java.util.List;
/**
- * The {@link Transitions.TransitionHandler} that handles freeform task maximizing and restoring
- * transitions.
+ * The {@link Transitions.TransitionHandler} that handles freeform task maximizing, closing, and
+ * restoring transitions.
*/
public class FreeformTaskTransitionHandler
implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
-
+ private static final int CLOSE_ANIM_DURATION = 400;
+ private final Context mContext;
private final Transitions mTransitions;
private final WindowDecorViewModel mWindowDecorViewModel;
+ private final DisplayController mDisplayController;
+ private final ShellExecutor mMainExecutor;
+ private final ShellExecutor mAnimExecutor;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
+ private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
+
public FreeformTaskTransitionHandler(
ShellInit shellInit,
Transitions transitions,
- WindowDecorViewModel windowDecorViewModel) {
+ Context context,
+ WindowDecorViewModel windowDecorViewModel,
+ DisplayController displayController,
+ ShellExecutor mainExecutor,
+ ShellExecutor animExecutor) {
mTransitions = transitions;
+ mContext = context;
mWindowDecorViewModel = windowDecorViewModel;
+ mDisplayController = displayController;
+ mMainExecutor = mainExecutor;
+ mAnimExecutor = animExecutor;
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -103,6 +125,14 @@
@NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
boolean transitionHandled = false;
+ final ArrayList<Animator> animations = new ArrayList<>();
+ final Runnable onAnimFinish = () -> {
+ if (!animations.isEmpty()) return;
+ mMainExecutor.execute(() -> {
+ mAnimations.remove(transition);
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ });
+ };
for (TransitionInfo.Change change : info.getChanges()) {
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
continue;
@@ -121,21 +151,45 @@
case WindowManager.TRANSIT_TO_BACK:
transitionHandled |= startMinimizeTransition(transition);
break;
+ case WindowManager.TRANSIT_CLOSE:
+ if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ transitionHandled |= startCloseTransition(transition, change,
+ finishT, animations, onAnimFinish);
+ }
+ break;
}
}
-
- mPendingTransitionTokens.remove(transition);
-
if (!transitionHandled) {
return false;
}
-
+ mAnimations.put(transition, animations);
+ // startT must be applied before animations start.
startT.apply();
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ mAnimExecutor.execute(() -> {
+ for (Animator anim : animations) {
+ anim.start();
+ }
+ });
+ // Run this here in case no animators are created.
+ onAnimFinish.run();
+ mPendingTransitionTokens.remove(transition);
return true;
}
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ ArrayList<Animator> animations = mAnimations.get(mergeTarget);
+ if (animations == null) return;
+ mAnimExecutor.execute(() -> {
+ for (Animator anim : animations) {
+ anim.end();
+ }
+ });
+
+ }
+
private boolean startChangeTransition(
IBinder transition,
int type,
@@ -165,6 +219,36 @@
return mPendingTransitionTokens.contains(transition);
}
+ private boolean startCloseTransition(IBinder transition, TransitionInfo.Change change,
+ SurfaceControl.Transaction finishT, ArrayList<Animator> animations,
+ Runnable onAnimFinish) {
+ if (!mPendingTransitionTokens.contains(transition)) return false;
+ int screenHeight = mDisplayController
+ .getDisplayLayout(change.getTaskInfo().displayId).height();
+ ValueAnimator animator = new ValueAnimator();
+ animator.setDuration(CLOSE_ANIM_DURATION)
+ .setFloatValues(0f, 1f);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ SurfaceControl sc = change.getLeash();
+ finishT.hide(sc);
+ Rect startBounds = new Rect(change.getTaskInfo().configuration.windowConfiguration
+ .getBounds());
+ animator.addUpdateListener(animation -> {
+ t.setPosition(sc, startBounds.left,
+ startBounds.top + (animation.getAnimatedFraction() * screenHeight));
+ t.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animations.remove(animator);
+ onAnimFinish.run();
+ }
+ });
+ animations.add(animator);
+ return true;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 64571e0..5ee5324 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -40,6 +40,9 @@
import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.desktopmode.DesktopModeController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -65,6 +68,8 @@
private RecentsTransitionHandler mRecentsHandler;
private StageCoordinator mSplitHandler;
private final KeyguardTransitionHandler mKeyguardHandler;
+ private DesktopModeController mDesktopModeController;
+ private DesktopTasksController mDesktopTasksController;
private static class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -81,6 +86,9 @@
/** Keyguard exit/occlude/unocclude transition. */
static final int TYPE_KEYGUARD = 5;
+ /** Recents Transition while in desktop mode. */
+ static final int TYPE_RECENTS_DURING_DESKTOP = 6;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -132,7 +140,9 @@
Optional<SplitScreenController> splitScreenControllerOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
Optional<RecentsTransitionHandler> recentsHandlerOptional,
- KeyguardTransitionHandler keyguardHandler) {
+ KeyguardTransitionHandler keyguardHandler,
+ Optional<DesktopModeController> desktopModeControllerOptional,
+ Optional<DesktopTasksController> desktopTasksControllerOptional) {
mPlayer = player;
mKeyguardHandler = keyguardHandler;
if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
@@ -149,6 +159,8 @@
if (mRecentsHandler != null) {
mRecentsHandler.addMixer(this);
}
+ mDesktopModeController = desktopModeControllerOptional.orElse(null);
+ mDesktopTasksController = desktopTasksControllerOptional.orElse(null);
}, this);
}
}
@@ -218,7 +230,8 @@
@Override
public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
- if (mRecentsHandler != null && mSplitHandler.isSplitScreenVisible()) {
+ if (mRecentsHandler != null && (mSplitHandler.isSplitScreenVisible()
+ || DesktopModeStatus.isActive(mPlayer.getContext()))) {
return this;
}
return null;
@@ -233,6 +246,13 @@
MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
mixed.mLeftoversHandler = mRecentsHandler;
mActiveTransitions.add(mixed);
+ } else if (DesktopModeStatus.isActive(mPlayer.getContext())) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "desktop mode is active, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
} else {
throw new IllegalStateException("Accepted a recents transition but don't know how to"
+ " handle it");
@@ -306,6 +326,9 @@
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
return animateKeyguard(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -582,6 +605,30 @@
return true;
}
+ private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ boolean consumed = mRecentsHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+ if (!consumed) {
+ return false;
+ }
+ //Sync desktop mode state (proto 1)
+ if (mDesktopModeController != null) {
+ mDesktopModeController.syncSurfaceState(info, finishTransaction);
+ return true;
+ }
+ //Sync desktop mode state (proto 2)
+ if (mDesktopTasksController != null) {
+ mDesktopTasksController.syncSurfaceState(info, finishTransaction);
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -625,6 +672,9 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ finishCallback);
} else {
throw new IllegalStateException("Playing a mixed transition with unknown type? "
+ mixed.mType);
@@ -650,6 +700,8 @@
mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
+ mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
index f81fc6f..6bba0d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
@@ -110,7 +110,7 @@
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
return source;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index a4cf149..21994a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -50,11 +50,11 @@
import com.android.wm.shell.unfold.UnfoldAnimationController;
import com.android.wm.shell.unfold.UnfoldBackgroundController;
+import dagger.Lazy;
+
import java.util.Optional;
import java.util.concurrent.Executor;
-import dagger.Lazy;
-
/**
* This helper class contains logic that calculates scaling and cropping parameters
* for the folding/unfolding animation. As an input it receives TaskInfo objects and
@@ -149,7 +149,7 @@
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
return source;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 39fb793..2267c75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -268,7 +268,10 @@
return false;
}
case MotionEvent.ACTION_MOVE: {
- int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
+ final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mIsDragging = true;
@@ -276,7 +279,10 @@
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
- int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
+ final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
final boolean wasDragging = mIsDragging;
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 9fd57d7..2fd34d9 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
@@ -385,6 +385,9 @@
case MotionEvent.ACTION_MOVE: {
final DesktopModeWindowDecoration decoration =
mWindowDecorByTaskId.get(mTaskId);
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
decoration.mTaskSurface, e.getRawY(dragPointerIdx)));
@@ -395,6 +398,9 @@
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
+ if (e.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = e.getPointerId(0);
+ }
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
// Position of the task is calculated by subtracting the raw location of the
// motion event (the location of the motion relative to the display) by the
@@ -405,7 +411,7 @@
mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
- position));
+ position, e.getRawY()));
final boolean wasDragging = mIsDragging;
mIsDragging = false;
return wasDragging;
@@ -814,8 +820,13 @@
@NonNull DesktopModeWindowDecoration windowDecoration,
@NonNull RunningTaskInfo taskInfo) {
final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
- final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
- getStatusBarHeight(taskInfo.displayId));
+ final Rect disallowedAreaForEndBounds;
+ if (DesktopModeStatus.isProto2Enabled()) {
+ disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
+ getStatusBarHeight(taskInfo.displayId));
+ } else {
+ disallowedAreaForEndBounds = null;
+ }
if (!DesktopModeStatus.isVeiledResizeEnabled()) {
return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 65b5a7a..58644b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -73,8 +73,11 @@
return mResultOfDownAction;
}
case ACTION_MOVE: {
+ if (ev.findPointerIndex(mDragPointerId) == -1) {
+ mDragPointerId = ev.getPointerId(0);
+ }
+ final int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
if (!mIsDragEvent) {
- int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
// Touches generate noisy moves, so only once the move is past the touch
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 58c78e6..39b9021 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -55,7 +55,7 @@
private final Rect mRepositionTaskBounds = new Rect();
// If a task move (not resize) finishes in this region, the positioner will not attempt to
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private final Rect mDisallowedAreaForEndBounds;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private int mCtrlType;
@@ -77,7 +77,7 @@
mDesktopWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
- mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
+ mDisallowedAreaForEndBounds = new Rect(disallowedAreaForEndBounds);
mTransactionSupplier = supplier;
mTransitions = transitions;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index ac5ff20..67ec6cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -248,6 +248,9 @@
mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
wct.addInsetsSource(mTaskInfo.token,
mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
+ wct.addInsetsSource(mTaskInfo.token,
+ mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
+ mCaptionInsetsRect);
} else {
startT.hide(mCaptionContainerSurface);
}
@@ -345,6 +348,8 @@
final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
wct.removeInsetsSource(mTaskInfo.token,
mOwner, 0 /* index */, WindowInsets.Type.captionBar());
+ wct.removeInsetsSource(mTaskInfo.token,
+ mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures());
mTaskOrganizer.applyTransaction(wct);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index b6696c7..e382a0f 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -23,14 +23,33 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-android_test {
- name: "WMShellFlickerTests",
+filegroup {
+ name: "WMShellFlickerTestsBase-src",
+ srcs: ["src/com/android/wm/shell/flicker/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsBubbles-src",
+ srcs: ["src/**/bubble/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsPip-src",
+ srcs: ["src/**/pip/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreen-src",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
+ "src/**/splitscreen/*.kt",
+ "src/**/splitscreen/benchmark/*.kt",
],
- manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+}
+
+java_defaults {
+ name: "WMShellFlickerTestsDefault",
+ manifest: "manifests/AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -40,16 +59,70 @@
libs: ["android.test.runner"],
static_libs: [
"androidx.test.ext.junit",
+ "flickertestapplib",
"flickerlib",
- "flickerlib-apphelpers",
"flickerlib-helpers",
- "truth-prebuilt",
- "app-helpers-core",
+ "platform-test-annotations",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-common-assertions",
"launcher-helper-lib",
"launcher-aosp-tapl",
- "wm-flicker-common-assertions",
- "wm-flicker-common-app-helpers",
- "platform-test-annotations",
- "flickertestapplib",
+ ],
+ data: [
+ ":FlickerTestApp",
+ "trace_config/*",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsOther",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestOther.xml"],
+ package_name: "com.android.wm.shell.flicker",
+ instrumentation_target_package: "com.android.wm.shell.flicker",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ exclude_srcs: [
+ ":WMShellFlickerTestsBubbles-src",
+ ":WMShellFlickerTestsPip-src",
+ ":WMShellFlickerTestsSplitScreen-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsBubbles",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestBubbles.xml"],
+ package_name: "com.android.wm.shell.flicker.bubbles",
+ instrumentation_target_package: "com.android.wm.shell.flicker.bubbles",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsBubbles-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsPip",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestPip.xml"],
+ package_name: "com.android.wm.shell.flicker.pip",
+ instrumentation_target_package: "com.android.wm.shell.flicker.pip",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsPip-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsSplitScreen",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
+ package_name: "com.android.wm.shell.flicker.splitscreen",
+ instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsSplitScreen-src",
],
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
deleted file mode 100644
index b5937ae..0000000
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright 2020 Google Inc. All Rights Reserved.
- -->
-<configuration description="Runs WindowManager Shell Flicker Tests">
- <option name="test-tag" value="FlickerTests" />
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- keeps the screen on during tests -->
- <option name="screen-always-on" value="on" />
- <!-- prevents the phone from restarting -->
- <option name="force-skip-system-props" value="true" />
- <!-- set WM tracing verbose level to all -->
- <option name="run-command" value="cmd window tracing level all" />
- <!-- set WM tracing to frame (avoid incomplete states) -->
- <option name="run-command" value="cmd window tracing frame" />
- <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
- <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
- <!-- ensure lock screen mode is swipe -->
- <option name="run-command" value="locksettings set-disabled false" />
- <!-- restart launcher to activate TAPL -->
- <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
- <!-- Ensure output directory is empty at the start -->
- <option name="run-command" value="rm -rf /sdcard/flicker" />
- <!-- Increase trace size: 20mb for WM and 80mb for SF -->
- <option name="run-command" value="cmd window tracing size 20480" />
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
- <option name="run-command" value="settings put system show_touches 1" />
- <option name="run-command" value="settings put system pointer_location 1" />
- <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
- <option name="teardown-command" value="settings delete system show_touches" />
- <option name="teardown-command" value="settings delete system pointer_location" />
- <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="WMShellFlickerTests.apk"/>
- <option name="test-file-name" value="FlickerTestApp.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="com.android.wm.shell.flicker"/>
- <option name="shell-timeout" value="6600s" />
- <option name="test-timeout" value="6000s" />
- <option name="hidden-api-checks" value="false" />
- </test>
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/flicker" />
- <option name="collect-on-run-ended-only" value="true" />
- <option name="clean-up" value="true" />
- </metrics_collector>
-</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
new file mode 100644
index 0000000..ffe6d6a2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
@@ -0,0 +1,99 @@
+<?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.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}">
+ <option name="test-tag" value="FlickerTests" />
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
+ <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
+ <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
+ <!-- ensure lock screen mode is swipe -->
+ <option name="run-command" value="locksettings set-disabled false" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ <!-- Ensure output directory is empty at the start -->
+ <option name="run-command" value="rm -rf /sdcard/flicker" />
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480" />
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="run-command" value="settings put system show_touches 1" />
+ <option name="run-command" value="settings put system pointer_location 1" />
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard" />
+ <option name="teardown-command" value="settings delete system show_touches" />
+ <option name="teardown-command" value="settings delete system pointer_location" />
+ <option name="teardown-command"
+ value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="{MODULE}.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk" />
+ </target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file"
+ key="trace_config.textproto"
+ value="/data/misc/perfetto-traces/trace_config.textproto"
+ />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="{PACKAGE}"/>
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ <option name="device-listeners" value="android.device.collectors.PerfettoListener" />
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg"
+ key="perfetto_config_file"
+ value="trace_config.textproto"
+ />
+ <option name="instrumentation-arg" key="per_run" value="true" />
+ </test>
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+ <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+ <option name="collect-on-run-ended-only" value="false" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/flicker" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
similarity index 100%
rename from libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
rename to libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml
new file mode 100644
index 0000000..437871f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.bubble">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.bubble"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml
new file mode 100644
index 0000000..cf642f6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml
new file mode 100644
index 0000000..5a8155a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.pip">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.pip"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml
new file mode 100644
index 0000000..887d8db
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.splitscreen">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.splitscreen"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto
new file mode 100644
index 0000000..406ada9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/trace_config/trace_config.textproto
@@ -0,0 +1,75 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 2500
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 30000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers: {
+ size_kb: 63488
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ # polled per-process memory counters and process/thread names.
+ # If you don't want the polled counters, remove the "process_stats_config"
+ # section, but keep the data source itself as it still provides on-demand
+ # thread/process naming for ftrace data below.
+ process_stats_config {
+ scan_all_processes_on_start: true
+ }
+ }
+}
+
+data_sources: {
+ config {
+ name: "linux.ftrace"
+ ftrace_config {
+ ftrace_events: "ftrace/print"
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ atrace_categories: "ss"
+ atrace_categories: "wm"
+ atrace_categories: "am"
+ atrace_categories: "aidl"
+ atrace_categories: "input"
+ atrace_categories: "binder_driver"
+ atrace_categories: "sched_process_exit"
+ atrace_apps: "com.android.server.wm.flicker.testapp"
+ atrace_apps: "com.android.systemui"
+ atrace_apps: "com.android.wm.shell.flicker"
+ atrace_apps: "com.android.wm.shell.flicker.other"
+ atrace_apps: "com.android.wm.shell.flicker.bubbles"
+ atrace_apps: "com.android.wm.shell.flicker.pip"
+ atrace_apps: "com.android.wm.shell.flicker.splitscreen"
+ atrace_apps: "com.google.android.apps.nexuslauncher"
+ }
+ }
+}
+
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
new file mode 100644
index 0000000..d38b848
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
@@ -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.wm.shell.bubbles.bar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.drawable.ColorDrawable;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.core.content.ContextCompat;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class BubbleBarHandleViewTest extends ShellTestCase {
+ private BubbleBarHandleView mHandleView;
+
+ @Before
+ public void setup() {
+ mHandleView = new BubbleBarHandleView(mContext);
+ }
+
+ @Test
+ public void testUpdateHandleColor_lightBg() {
+ mHandleView.updateHandleColor(false /* isRegionDark */, false /* animated */);
+
+ assertTrue(mHandleView.getClipToOutline());
+ assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
+ ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
+ assertEquals(bgDrawable.getColor(),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_dark));
+ }
+
+ @Test
+ public void testUpdateHandleColor_darkBg() {
+ mHandleView.updateHandleColor(true /* isRegionDark */, false /* animated */);
+
+ assertTrue(mHandleView.getClipToOutline());
+ assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
+ ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
+ assertEquals(bgDrawable.getColor(),
+ ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_light));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
new file mode 100644
index 0000000..9da5ab6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CURSOR_HOVER_STATES_ENABLED;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.view.InputDevice;
+import android.view.InsetsState;
+import android.view.MotionEvent;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayImeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link DividerView} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DividerViewTest extends ShellTestCase {
+ private @Mock SplitWindowManager.ParentContainerCallbacks mCallbacks;
+ private @Mock SplitLayout.SplitLayoutHandler mSplitLayoutHandler;
+ private @Mock DisplayImeController mDisplayImeController;
+ private @Mock ShellTaskOrganizer mTaskOrganizer;
+ private SplitLayout mSplitLayout;
+ private DividerView mDividerView;
+
+ @Before
+ @UiThreadTest
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ Configuration configuration = getConfiguration();
+ mSplitLayout = new SplitLayout("TestSplitLayout", mContext, configuration,
+ mSplitLayoutHandler, mCallbacks, mDisplayImeController, mTaskOrganizer,
+ SplitLayout.PARALLAX_NONE);
+ SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
+ mContext,
+ configuration, mCallbacks);
+ splitWindowManager.init(mSplitLayout, new InsetsState());
+ mDividerView = spy((DividerView) splitWindowManager.getDividerView());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testHoverDividerView() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ "true", false);
+
+ Rect dividerBounds = mSplitLayout.getDividerBounds();
+ int x = dividerBounds.centerX();
+ int y = dividerBounds.centerY();
+ long downTime = SystemClock.uptimeMillis();
+ mDividerView.onHoverEvent(getMotionEvent(downTime, MotionEvent.ACTION_HOVER_ENTER, x, y));
+
+ verify(mDividerView, times(1)).setHovering();
+
+ mDividerView.onHoverEvent(getMotionEvent(downTime, MotionEvent.ACTION_HOVER_EXIT, x, y));
+
+ verify(mDividerView, times(1)).releaseHovering();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CURSOR_HOVER_STATES_ENABLED,
+ "false", false);
+ }
+
+ private static MotionEvent getMotionEvent(long eventTime, int action, float x, float y) {
+ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = 0;
+ properties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+
+ MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+ coords.pressure = 1;
+ coords.size = 1;
+ coords.x = x;
+ coords.y = y;
+
+ return MotionEvent.obtain(eventTime, eventTime, action, 1,
+ new MotionEvent.PointerProperties[]{properties},
+ new MotionEvent.PointerCoords[]{coords}, 0, 0, 1.0f, 1.0f, 0, 0,
+ InputDevice.SOURCE_TOUCHSCREEN, 0);
+ }
+
+ private static Configuration getConfiguration() {
+ final Configuration configuration = new Configuration();
+ configuration.unset();
+ configuration.orientation = ORIENTATION_LANDSCAPE;
+ configuration.windowConfiguration.setRotation(0);
+ configuration.windowConfiguration.setBounds(new Rect(0, 0, 1080, 2160));
+ return configuration;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 3bc2f0e..17c0463 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -313,6 +313,65 @@
assertThat(tasks.first()).isEqualTo(6)
}
+ @Test
+ fun setStashed_stateIsUpdatedForTheDisplay() {
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ assertThat(repo.isStashed(DEFAULT_DISPLAY)).isTrue()
+ assertThat(repo.isStashed(SECOND_DISPLAY)).isFalse()
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ assertThat(repo.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
+ fun setStashed_notifyListener() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isFalse()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(2)
+ }
+
+ @Test
+ fun setStashed_secondCallDoesNotNotify() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
+ fun setStashed_tracksPerDisplay() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedOnSecondaryDisplay).isFalse()
+
+ repo.setStashed(SECOND_DISPLAY, true)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedOnSecondaryDisplay).isTrue()
+
+ repo.setStashed(DEFAULT_DISPLAY, false)
+ executor.flushAll()
+ assertThat(listener.stashedOnDefaultDisplay).isFalse()
+ assertThat(listener.stashedOnSecondaryDisplay).isTrue()
+ }
+
class TestListener : DesktopModeTaskRepository.ActiveTasksListener {
var activeChangesOnDefaultDisplay = 0
var activeChangesOnSecondaryDisplay = 0
@@ -332,6 +391,12 @@
var visibleChangesOnDefaultDisplay = 0
var visibleChangesOnSecondaryDisplay = 0
+ var stashedOnDefaultDisplay = false
+ var stashedOnSecondaryDisplay = false
+
+ var stashedChangesOnDefaultDisplay = 0
+ var stashedChangesOnSecondaryDisplay = 0
+
override fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {
when (displayId) {
DEFAULT_DISPLAY -> {
@@ -345,6 +410,20 @@
else -> fail("Visible task listener received unexpected display id: $displayId")
}
}
+
+ override fun onStashedChanged(displayId: Int, stashed: Boolean) {
+ when (displayId) {
+ DEFAULT_DISPLAY -> {
+ stashedOnDefaultDisplay = stashed
+ stashedChangesOnDefaultDisplay++
+ }
+ SECOND_DISPLAY -> {
+ stashedOnSecondaryDisplay = stashed
+ stashedChangesOnDefaultDisplay++
+ }
+ else -> fail("Visible task listener received unexpected display id: $displayId")
+ }
+ }
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 1335ebf..e3dd449 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -345,6 +345,18 @@
}
@Test
+ fun moveTaskToFront_postsWctWithReorderOp() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+
+ controller.moveTaskToFront(task1)
+
+ val wct = getLatestWct(expectTransition = TRANSIT_TO_FRONT)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertReorderAt(index = 0, task1)
+ }
+
+ @Test
fun moveToNextDisplay_noOtherDisplays() {
whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
@@ -451,6 +463,27 @@
}
@Test
+ fun handleRequest_fullscreenTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+
+ val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
+ markTaskHidden(stashedFreeformTask)
+
+ val fullscreenTask = createFullscreenTask(DEFAULT_DISPLAY)
+
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ val result = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+ assertThat(result).isNotNull()
+ result!!.assertReorderSequence(stashedFreeformTask, fullscreenTask)
+ assertThat(result.changes[fullscreenTask.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
+
+ // Stashed state should be cleared
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
fun handleRequest_freeformTask_freeformVisible_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -501,6 +534,25 @@
}
@Test
+ fun handleRequest_freeformTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+
+ val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY)
+ markTaskHidden(stashedFreeformTask)
+
+ val freeformTask = createFreeformTask(DEFAULT_DISPLAY)
+
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ val result = controller.handleRequest(Binder(), createTransition(freeformTask))
+ assertThat(result).isNotNull()
+ result?.assertReorderSequence(stashedFreeformTask, freeformTask)
+
+ // Stashed state should be cleared
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ }
+
+ @Test
fun handleRequest_notOpenOrToFrontTransition_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -539,6 +591,25 @@
assertThat(controller.handleRequest(Binder(), createTransition(task))).isNull()
}
+ @Test
+ fun stashDesktopApps_stateUpdates() {
+ controller.stashDesktopApps(DEFAULT_DISPLAY)
+
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isTrue()
+ assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isFalse()
+ }
+
+ @Test
+ fun hideStashedDesktopApps_stateUpdates() {
+ desktopModeTaskRepository.setStashed(DEFAULT_DISPLAY, true)
+ desktopModeTaskRepository.setStashed(SECOND_DISPLAY, true)
+ controller.hideStashedDesktopApps(DEFAULT_DISPLAY)
+
+ assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse()
+ // Check that second display is not affected
+ assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isTrue()
+ }
+
private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
val task = createFreeformTask(displayId)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 5a2326b..f941e95 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -316,7 +316,8 @@
releaseOrder.verify(t).remove(captionContainerSurface);
releaseOrder.verify(t).remove(decorContainerSurface);
releaseOrder.verify(t).apply();
- verify(mMockWindowContainerTransaction)
+ // Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
+ verify(mMockWindowContainerTransaction, Mockito.times(2))
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
}
diff --git a/packages/CarrierDefaultApp/assets/slice_purchase_test.html b/packages/CarrierDefaultApp/assets/slice_purchase_test.html
index 67d2184..917276b 100644
--- a/packages/CarrierDefaultApp/assets/slice_purchase_test.html
+++ b/packages/CarrierDefaultApp/assets/slice_purchase_test.html
@@ -20,7 +20,7 @@
<meta charset="UTF-8">
<meta name="description" content="
This is a HTML page that calls and verifies responses from the @JavascriptInterface functions of
- SlicePurchaseWebInterface. Test slice purchase application behavior using ADB shell commands and
+ DataBoostWebServiceFlow. Test slice purchase application behavior using ADB shell commands and
the APIs below:
FROM TERMINAL:
@@ -65,8 +65,8 @@
<p id="requested_capability"></p>
<h2>Notify purchase successful</h2>
- <button type="button" onclick="testNotifyPurchaseSuccessful(60000)">
- Notify purchase successful for 1 minute
+ <button type="button" onclick="testNotifyPurchaseSuccessful()">
+ Notify purchase successful
</button>
<p id="purchase_successful"></p>
@@ -75,5 +75,11 @@
Notify purchase failed
</button>
<p id="purchase_failed"></p>
+
+ <h2>Dismiss flow</h2>
+ <button type="button" onclick="testDismissFlow()">
+ Dismiss flow
+ </button>
+ <p id="dismiss_flow"></p>
</body>
</html>
diff --git a/packages/CarrierDefaultApp/assets/slice_purchase_test.js b/packages/CarrierDefaultApp/assets/slice_purchase_test.js
index 02c4fea..be397a1 100644
--- a/packages/CarrierDefaultApp/assets/slice_purchase_test.js
+++ b/packages/CarrierDefaultApp/assets/slice_purchase_test.js
@@ -15,19 +15,25 @@
*/
function testGetRequestedCapability() {
- let capability = SlicePurchaseWebInterface.getRequestedCapability();
+ let capability = DataBoostWebServiceFlow.getRequestedCapability();
document.getElementById("requested_capability").innerHTML =
"Premium capability requested: " + capability;
}
-function testNotifyPurchaseSuccessful(duration_ms_long = 0) {
- SlicePurchaseWebInterface.notifyPurchaseSuccessful(duration_ms_long);
+function testNotifyPurchaseSuccessful() {
+ DataBoostWebServiceFlow.notifyPurchaseSuccessful();
document.getElementById("purchase_successful").innerHTML =
- "Notified purchase success for duration: " + duration_ms_long;
+ "Notified purchase successful.";
}
function testNotifyPurchaseFailed(failure_code = 0, failure_reason = "unknown") {
- SlicePurchaseWebInterface.notifyPurchaseFailed(failure_code, failure_reason);
+ DataBoostWebServiceFlow.notifyPurchaseFailed(failure_code, failure_reason);
document.getElementById("purchase_failed").innerHTML =
"Notified purchase failed.";
}
+
+function testDismissFlow() {
+ DataBoostWebServiceFlow.dismissFlow();
+ document.getElementById("dismiss_flow").innerHTML =
+ "Called dismiss flow.";
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseWebInterface.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/DataBoostWebServiceFlow.java
similarity index 71%
rename from packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseWebInterface.java
rename to packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/DataBoostWebServiceFlow.java
index 8547898..4500a22 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseWebInterface.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/DataBoostWebServiceFlow.java
@@ -24,13 +24,13 @@
import com.android.phone.slice.SlicePurchaseController;
/**
- * Slice purchase web interface class allowing carrier websites to send responses back to the
+ * Data boost web service flow interface allowing carrier websites to send responses back to the
* slice purchase application using JavaScript.
*/
-public class SlicePurchaseWebInterface {
+public class DataBoostWebServiceFlow {
@NonNull SlicePurchaseActivity mActivity;
- public SlicePurchaseWebInterface(@NonNull SlicePurchaseActivity activity) {
+ public DataBoostWebServiceFlow(@NonNull SlicePurchaseActivity activity) {
mActivity = activity;
}
@@ -41,7 +41,7 @@
* This can be called using the JavaScript below:
* <script type="text/javascript">
* function getRequestedCapability(duration) {
- * SlicePurchaseWebInterface.getRequestedCapability();
+ * DataBoostWebServiceFlow.getRequestedCapability();
* }
* </script>
*/
@@ -57,16 +57,14 @@
*
* This can be called using the JavaScript below:
* <script type="text/javascript">
- * function notifyPurchaseSuccessful(duration_ms_long = 0) {
- * SlicePurchaseWebInterface.notifyPurchaseSuccessful(duration_ms_long);
+ * function notifyPurchaseSuccessful() {
+ * DataBoostWebServiceFlow.notifyPurchaseSuccessful();
* }
* </script>
- *
- * @param duration The duration for which the premium capability is purchased in milliseconds.
*/
@JavascriptInterface
- public void notifyPurchaseSuccessful(long duration) {
- mActivity.onPurchaseSuccessful(duration);
+ public void notifyPurchaseSuccessful() {
+ mActivity.onPurchaseSuccessful();
}
/**
@@ -76,7 +74,7 @@
* This can be called using the JavaScript below:
* <script type="text/javascript">
* function notifyPurchaseFailed(failure_code = 0, failure_reason = "unknown") {
- * SlicePurchaseWebInterface.notifyPurchaseFailed();
+ * DataBoostWebServiceFlow.notifyPurchaseFailed();
* }
* </script>
*
@@ -90,4 +88,21 @@
@Nullable String failureReason) {
mActivity.onPurchaseFailed(failureCode, failureReason);
}
+
+ /**
+ * Interface method allowing the carrier website to notify the slice purchase application that
+ * the service flow ended prematurely. This can be due to user action, an error in the
+ * web sheet logic, or an error on the network side.
+ *
+ * This can be called using the JavaScript below:
+ * <script type="text/javascript">
+ * function dismissFlow() {
+ * DataBoostWebServiceFlow.dismissFlow();
+ * }
+ * </script>
+ */
+ @JavascriptInterface
+ public void dismissFlow() {
+ mActivity.onDismissFlow();
+ }
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index 946185a..2530257d6 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -27,26 +27,25 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
+import android.webkit.CookieManager;
import android.webkit.WebView;
import com.android.phone.slice.SlicePurchaseController;
import java.net.URL;
-import java.util.concurrent.TimeUnit;
/**
* Activity that launches when the user clicks on the performance boost notification.
* This will open a {@link WebView} for the carrier website to allow the user to complete the
* premium capability purchase.
* The carrier website can get the requested premium capability using the JavaScript interface
- * method {@code SlicePurchaseWebInterface.getRequestedCapability()}.
+ * method {@code DataBoostWebServiceFlow.getRequestedCapability()}.
* If the purchase is successful, the carrier website shall notify the slice purchase application
* using the JavaScript interface method
- * {@code SlicePurchaseWebInterface.notifyPurchaseSuccessful(duration)}, where {@code duration} is
- * the optional duration of the performance boost.
+ * {@code DataBoostWebServiceFlow.notifyPurchaseSuccessful()}.
* If the purchase was not successful, the carrier website shall notify the slice purchase
* application using the JavaScript interface method
- * {@code SlicePurchaseWebInterface.notifyPurchaseFailed(code, reason)}, where {@code code} is the
+ * {@code DataBoostWebServiceFlow.notifyPurchaseFailed(code, reason)}, where {@code code} is the
* {@link SlicePurchaseController.FailureCode} indicating the reason for failure and {@code reason}
* is the human-readable reason for failure if the failure code is
* {@link SlicePurchaseController#FAILURE_CODE_UNKNOWN}.
@@ -118,15 +117,11 @@
setupWebView();
}
- protected void onPurchaseSuccessful(long duration) {
+ protected void onPurchaseSuccessful() {
logd("onPurchaseSuccessful: Carrier website indicated successfully purchased premium "
- + "capability " + TelephonyManager.convertPremiumCapabilityToString(mCapability)
- + (duration > 0 ? " for " + TimeUnit.MILLISECONDS.toMinutes(duration) + " minutes."
- : "."));
- Intent intent = new Intent();
- intent.putExtra(SlicePurchaseController.EXTRA_PURCHASE_DURATION, duration);
- SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(mApplicationContext,
- mIntent, SlicePurchaseController.EXTRA_INTENT_SUCCESS, intent);
+ + "capability " + TelephonyManager.convertPremiumCapabilityToString(mCapability));
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
+ mIntent, SlicePurchaseController.EXTRA_INTENT_SUCCESS);
finishAndRemoveTask();
}
@@ -143,6 +138,14 @@
finishAndRemoveTask();
}
+ protected void onDismissFlow() {
+ logd("onDismissFlow: Dismiss flow called while purchasing premium capability "
+ + TelephonyManager.convertPremiumCapabilityToString(mCapability));
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
+ mIntent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED);
+ finishAndRemoveTask();
+ }
+
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
// Pressing back in the WebView will go to the previous page instead of closing
@@ -174,11 +177,17 @@
// Create WebView
mWebView = new WebView(this);
+ // Clear any cookies and state that might be saved from previous sessions
+ CookieManager.getInstance().removeAllCookies(null);
+ CookieManager.getInstance().flush();
+ mWebView.clearCache(true);
+ mWebView.clearHistory();
+
// Enable JavaScript for the carrier purchase website to send results back to
// the slice purchase application.
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(
- new SlicePurchaseWebInterface(this), "SlicePurchaseWebInterface");
+ new DataBoostWebServiceFlow(this), "DataBoostWebServiceFlow");
// Display WebView
setContentView(mWebView);
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
index daf0b42..cc103fa 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
@@ -53,7 +53,9 @@
private static final int PHONE_ID = 0;
@Mock PendingIntent mPendingIntent;
+ @Mock PendingIntent mSuccessfulIntent;
@Mock PendingIntent mCanceledIntent;
+ @Mock PendingIntent mRequestFailedIntent;
@Mock CarrierConfigManager mCarrierConfigManager;
@Mock NotificationManager mNotificationManager;
@Mock PersistableBundle mPersistableBundle;
@@ -107,25 +109,28 @@
doReturn(true).when(mCanceledIntent).isBroadcast();
doReturn(mCanceledIntent).when(spiedIntent).getParcelableExtra(
eq(SlicePurchaseController.EXTRA_INTENT_CANCELED), eq(PendingIntent.class));
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mSuccessfulIntent).getCreatorPackage();
+ doReturn(true).when(mSuccessfulIntent).isBroadcast();
+ doReturn(mSuccessfulIntent).when(spiedIntent).getParcelableExtra(
+ eq(SlicePurchaseController.EXTRA_INTENT_SUCCESS), eq(PendingIntent.class));
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mRequestFailedIntent)
+ .getCreatorPackage();
+ doReturn(true).when(mRequestFailedIntent).isBroadcast();
+ doReturn(mRequestFailedIntent).when(spiedIntent).getParcelableExtra(
+ eq(SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED), eq(PendingIntent.class));
mSlicePurchaseActivity = startActivity(spiedIntent, null, null);
}
@Test
public void testOnPurchaseSuccessful() throws Exception {
- int duration = 5 * 60 * 1000; // 5 minutes
- int invalidDuration = -1;
- mSlicePurchaseActivity.onPurchaseSuccessful(duration);
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mPendingIntent).send(eq(mContext), eq(0), intentCaptor.capture());
- Intent intent = intentCaptor.getValue();
- assertEquals(duration, intent.getLongExtra(
- SlicePurchaseController.EXTRA_PURCHASE_DURATION, invalidDuration));
+ mSlicePurchaseActivity.onPurchaseSuccessful();
+ verify(mSuccessfulIntent).send();
}
@Test
public void testOnPurchaseFailed() throws Exception {
- int failureCode = SlicePurchaseController.FAILURE_CODE_SERVER_UNREACHABLE;
+ int failureCode = SlicePurchaseController.FAILURE_CODE_CARRIER_URL_UNAVAILABLE;
String failureReason = "Server unreachable";
mSlicePurchaseActivity.onPurchaseFailed(failureCode, failureReason);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -142,4 +147,10 @@
mSlicePurchaseActivity.onDestroy();
verify(mCanceledIntent).send();
}
+
+ @Test
+ public void testOnDismissFlow() throws Exception {
+ mSlicePurchaseActivity.onDismissFlow();
+ verify(mRequestFailedIntent).send();
+ }
}
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index aae30df..a0b3469 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -144,7 +144,7 @@
android:visibility="gone"
android:duplicateParentState="true"
android:clickable="false"
- android:text="@string/consent_no" />
+ android:text="@string/consent_cancel" />
</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 2c0af5d..1082c0a 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> bestuur te word"</string>
- <string name="summary_watch" msgid="898569637110705523">"Hierdie app is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om inligting te sinkroniseer, soos die naam van iemand wat bel, interaksie met jou kennisgewings te hê, en sal toegang tot jou Foon-, SMS-, Kontakte-, Kalender-, Oproeprekords-, en Toestelle in die Omtrek-toestemmings hê."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Hierdie app sal toegelaat word om inligting te sinkroniseer, soos die naam van iemand wat bel, en sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> hê"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Kies ’n toestel wat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> moet bestuur"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Kies ’n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om op te stel"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Hierdie app sal toegelaat word om inligting te sinkroniseer, soos die naam van iemand wat bel, en sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hê"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te bestuur?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"bril"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Hierdie app is nodig om <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê en sal toegang tot jou Foon-, SMS-, Kontakte-, Mikrofoon-, en Toestelle in die Omtrek-toestemmings hê."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Hierdie app sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> hê"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"toestel"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Hierdie app sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hê"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toestemming om apps tussen jou toestelle te stroom"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Laat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> toe om hierdie handeling uit te voer?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en ander stelselkenmerke na toestelle in die omtrek te stroom"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en die gekose toestel"</string>
<string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
<string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Kanselleer"</string>
<string name="consent_back" msgid="2560683030046918882">"Terug"</string>
<string name="permission_expand" msgid="893185038020887411">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> uit"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> in"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index b8964b5..a625307 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲደርስ ይፈቀድለት?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
- <string name="chooser_title" msgid="2262294130493605839">"በ<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
- <string name="summary_watch" msgid="898569637110705523">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> እንደ የሚደውል ሰው ስም፣ ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ ዕውቅያዎች፣ የቀን መቁጠሪያ፣ የጥሪ ምዝግብ ማስታወሻዎች እና በአቅራቢያ ያሉ መሣሪያዎችን መድረስ ያሉ መረጃዎችን እንዲያሰምር ይፈቀድለታል።"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን እንዲያሰምር እና እነዚህን ፈቃዶች በእርስዎ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ላይ እንዲደርስ ይፈቀድለታል"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የሚያስተዳድረው መሣሪያ ይምረጡ"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"የሚያዋቅሩት <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን እንዲያሰምር እና እነዚህን ፈቃዶች በእርስዎ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ላይ እንዲደርስ ይፈቀድለታል"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲያስተዳድር ይፈቅዳሉ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"መነጽሮች"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ይህ መተግበሪያ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ን ለማስተዳደር ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ ዕውቂያዎች፣ ማይክሮፎን እና በአቅራቢያ ያሉ መሣሪያዎች ፈቃዶችን እንዲደርስ ይፈቀድለታል።"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ይህ መተግበሪያ በእርስዎ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ላይ እነዚህን ፈቃዶች እንዲደርስ ይፈቀድለታል"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"መሣሪያ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ይህ መተግበሪያ በእርስዎ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ላይ እነዚህን ፈቃዶች እንዲደርስ ይፈቀድለታል"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን በዥረት ለመልቀቅ የእርስዎን <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ይህን እርምጃ እንዲወስድ ፈቃድ ይሰጠው?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> በመወከል በአቅራቢያ ላሉ መሣሪያዎች መተግበሪያዎች እና ሌሎች የስርዓት ባህሪያትን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና <xliff:g id="DEVICE_NAME">%1$s</xliff:g> መካከል ማስመር ይችላል"</string>
<string name="summary_generic" msgid="1761976003668044801">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና በተመረጠው መሣሪያ መካከል ማስመር ይችላል"</string>
<string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
<string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ይቅር"</string>
<string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ዘርጋ"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ሰብስብ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 3a4a211..f15d71f 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
<string name="confirmation_title" msgid="4593465730772390351">"هل تريد السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"الساعة"</string>
- <string name="chooser_title" msgid="2262294130493605839">"اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديرها تطبيق <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"هذا التطبيق مطلوب لإدارة \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". سيتم السماح لتطبيق \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" بمزامنة المعلومات، مثلاً اسم المتصل، والتفاعل مع الإشعارات والوصول إلى هاتفك، والرسائل القصيرة، وجهات الاتصال، والتقويم، وسجلات المكالمات وأذونات الأجهزة المجاورة."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"سيتم السماح لهذا التطبيق بمزامنة المعلومات، مثلاً اسم المتصل، والوصول إلى الأذونات التالية على <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"اختيار جهاز ليديره تطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"اختيار \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" لإعداده"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"سيتم السماح لهذا التطبيق بمزامنة المعلومات، مثلاً اسم المتصل، والوصول إلى هذه الأذونات على \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بإدارة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"النظارة"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"يجب توفّر هذا التطبيق لإدارة \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". سيتم السماح لتطبيق \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والميكروفون والأجهزة المجاورة."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"سيتم السماح لهذا التطبيق بالوصول إلى الأذونات التالية على <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"جهاز"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"سيتم السماح لهذا التطبيق بالوصول إلى هذه الأذونات على \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"يطلب تطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" لبثّ محتوى التطبيقات بين أجهزتك."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"هل تريد السماح للتطبيق <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> باتّخاذ هذا الإجراء؟"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" لبثّ التطبيقات وميزات النظام الأخرى إلى أجهزتك المجاورة."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"سيتمكّن هذا التطبيق من مزامنة المعلومات، مثل اسم المتصل، بين هاتفك و\"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="summary_generic" msgid="1761976003668044801">"سيتمكّن هذا التطبيق من مزامنة المعلومات، مثل اسم المتصل، بين هاتفك والجهاز المحدّد."</string>
<string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
<string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"إلغاء"</string>
<string name="consent_back" msgid="2560683030046918882">"رجوع"</string>
<string name="permission_expand" msgid="893185038020887411">"توسيع <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"تصغير <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 1ac0ed3..4dfe368 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> এক্সেছ কৰিবলৈ দিবনে?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
- <string name="summary_watch" msgid="898569637110705523">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিবলৈ, আপোনাৰ জাননীৰ সৈতে ভাব-বিনিময় কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক, কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"এই এপ্টোক ফ’ন কৰা লোকৰ নামৰ দৰে তথ্য ছিংক কৰিবলৈ আৰু আপোনাৰ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>এ পৰিচালনা কৰিবলগীয়া এটা ডিভাইচ বাছনি কৰক"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ছেট আপ কৰিবলৈ এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"এই এপ্টোক ফ’ন কৰা লোকৰ নামৰ দৰে তথ্য ছিংক কৰিবলৈ আৰু আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> পৰিচালনা কৰিবলৈ দিবনে?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"চছ্মা"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ অনুমতিসমূহৰ সৈতে ভাব-বিনিময় কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক, মাইক্ৰ’ফ’ন আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতিসমূহ এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"এই এপ্টোক আপোনাৰ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইচ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"এই এপ্টোক আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্ ষ্ট্ৰীম কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ক এই কাৰ্যটো সম্পাদন কৰিবলৈ দিবনে?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ নিকটৱৰ্তী ডিভাইচত এপ্ আৰু ছিষ্টেমৰ অন্য সুবিধাসমূহ ষ্ট্ৰীম কৰাৰ অনুমতি দিবলৈ অনুৰোধ জনাইছে"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"এই এপ্টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string>
<string name="summary_generic" msgid="1761976003668044801">"এই এপ্টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা ডিভাইচটোৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string>
<string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
<string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"বাতিল কৰক"</string>
<string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বিস্তাৰ কৰক"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> সংকোচন কৰক"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 79a045d..9fd055c 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına daxil olmaq icazəsi verilsin?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" msgid="898569637110705523">"Tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazını idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> zəng edənin adı kimi məlumatları sinxronlaşdıracaq, bildirişlərə giriş edəcək, habelə Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihazlar üzrə icazələrə daxil olacaq."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Bu tətbiq zəng edənin adı kimi məlumatları sinxronlaşdıra, <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> bu icazələrə daxil ola biləcək"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tərəfindən idarə ediləcək cihaz seçin"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Ayarlamaq üçün <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Bu tətbiq zəng edənin adı kimi məlumatları sinxronlaşdıra, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> bu icazələrə daxil ola biləcək"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazını idarə etmək icazəsi verilsin?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"eynək"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazını idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərə, Telefon, SMS, Kontaktlar, Mikrofon və Yaxınlıqdakı cihazlar icazələrinə giriş əldə edəcək."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Bu tətbiq <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> bu icazələrə daxil ola biləcək"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"cihazda"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> bu icazələrə daxil ola biləcək"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> adından cihazlar arasında tətbiqləri yayımlamaq icazəsi istəyir"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazına bu əməliyyatı yerinə yetirmək icazəsi verilsin?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından tətbiq və digər sistem funksiyalarını yaxınlıqdakı cihazlara yayımlamaq icazəsi sitəyir"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> arasında sinxronlaşdıracaq"</string>
<string name="summary_generic" msgid="1761976003668044801">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə seçilmiş cihaz arasında sinxronlaşdıracaq"</string>
<string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
<string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Ləğv edin"</string>
<string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
<string name="permission_expand" msgid="893185038020887411">"Genişləndirin: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Yığcamlaşdırın: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index bb16290..9e3b711 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za sinhronizovanje informacija, poput osobe koja upućuje poziv, za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, kalendar, evidencije poziva i uređaje u blizini."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Ovoj aplikaciji će biti dozvoljeno da sinhronizuje podatke, poput imena osobe koja upućuje poziv, i pristupa tim dozvolama na vašem uređaju (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite da podesite"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Ovoj aplikaciji će biti dozvoljeno da sinhronizuje podatke, poput imena osobe koja upućuje poziv, i pristupa tim dozvolama na vašem uređaju (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite li da dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"naočare"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, mikrofon i uređaje u blizini."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Ovoj aplikaciji će biti dozvoljeno da pristupa ovim dozvolama na vašem uređaju (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Ovoj aplikaciji će biti dozvoljeno da pristupa ovim dozvolama na vašem uređaju (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za strimovanje aplikacija između uređaja"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Želite li da dozvolite da <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> obavi ovu radnju?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije i druge sistemske funkcije na uređaje u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i odabranog uređaja"</string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
<string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
<string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Skupi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 9c12f5a..b80e177 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -19,13 +19,17 @@
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ да прылады <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць), узаемадзейнічаць з вашымі апавяшчэннямі, а таксама атрымае доступ да тэлефона, SMS, кантактаў, календара, журналаў выклікаў і прылад паблізу."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) на вашай прыладзе \"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>\" і атрымае наступныя дазволы"</string>
+ <!-- no translation found for chooser_title_non_profile (6035023914517087400) -->
+ <skip />
+ <!-- no translation found for chooser_title (2235819929238267637) -->
+ <skip />
+ <!-- no translation found for summary_watch (7962014927042971830) -->
+ <skip />
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"акуляры"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа ўзаемадзейнічаць з вашымі апавяшчэннямі і атрымае доступ да тэлефона, SMS, кантактаў, мікрафона і прылад паблізу."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Гэта праграма будзе мець на вашай прыладзе \"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>\" наступныя дазволы"</string>
+ <!-- no translation found for profile_name_glasses (3506504967216601277) -->
+ <skip />
+ <!-- no translation found for summary_glasses (2872254734959842579) -->
+ <skip />
<string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" на трансляцыю праграм паміж вашымі прыладамі"</string>
@@ -38,10 +42,11 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Дазволіць прыладзе <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> выканаць гэта дзеянне?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на перадачу плынню змесціва праграм і іншых функцый сістэмы на прылады паблізу"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string>
<string name="summary_generic" msgid="1761976003668044801">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і выбранай прыладай"</string>
<string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
+ <!-- no translation found for consent_cancel (5655005528379285841) -->
+ <skip />
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Разгарнуць <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Згарнуць <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 4df4177..80b301b 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Да се разреши ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> за управление от <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи право да синхронизира различна информация, като например името на обаждащия се, да взаимодейства с известията ви и достъп до разрешенията за телефона, SMS съобщенията, контактите, календара, списъците с обажданията и устройствата в близост."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Това приложение ще получи право да синхронизира различна информация, като например името на обаждащия се, и достъп до следните разрешения за вашия <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете устройство, което да се управлява от <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, за да го настроите"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Това приложение ще получи право да синхронизира различна информация, като например името на обаждащия се, и достъп до следните разрешения за вашия <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешавате ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"очилата"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Приложението <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи право да взаимодейства с известията ви, както и достъп до разрешенията за телефона, SMS съобщенията, контактите, микрофона и устройствата в близост."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Това приложение ще има достъп до следните разрешения за вашия <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"устройство"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Това приложение ще има достъп до следните разрешения за вашето <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> да предава поточно приложения между устройствата ви"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Разрешавате ли на <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> да предприема това действие?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно приложения и други системни функции към устройства в близост"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и избраното устройство"</string>
<string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
<string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Отказ"</string>
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Разгъване на <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Свиване на <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 735b620..d789ab9 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> অ্যাক্সেস করার অনুমতি দেবেন?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ম্যানেজ করবে"</string>
- <string name="summary_watch" msgid="898569637110705523">"আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপটি প্রয়োজন। <xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপকে কলারের নাম ও আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করা সংক্রান্ত তথ্য সিঙ্কের অনুমতি দেওয়া হবে এবং আপনার ফোন, এসএমএস, পরিচিতি, ক্যালেন্ডার, কল লগ এবং আশেপাশের ডিভাইস ব্যবহার করার অনুমতির মতো তথ্যে অ্যাক্সেস দেওয়া হবে।"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"এই অ্যাপকে, কল করছেন এমন কোনও ব্যক্তির নামের মতো তথ্য সিঙ্ক এবং আপনার <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করতে দেওয়া হবে"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ম্যানেজ করা যাবে এমন একটি ডিভাইস বেছে নিন"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"সেট-আপ করতে কোনও <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"এই অ্যাপকে, কল করছেন এমন কোনও ব্যক্তির নামের মতো তথ্য সিঙ্ক করতে এবং আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করতে দেওয়া হবে"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"আপনি কি <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-কে অনুমতি দেবেন?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"চশমা"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপ দরকার। <xliff:g id="APP_NAME">%2$s</xliff:g>-কে আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করার এবং ফোন, এসএমএস, পরিচিতি, মাইক্রোফোন ও আশেপাশের ডিভাইসের অনুমতি অ্যাক্সেস করতে দেওয়া হবে।"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"এই অ্যাপ আপনার <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করতে পারবে"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইস"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"এই অ্যাপ আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করতে পারবে"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"আপনার ডিভাইসগুলির মধ্যে অ্যাপ স্ট্রিম করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-কে এই কাজটি করতে দেবেন?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"আশেপাশের ডিভাইসে অ্যাপ ও অন্যান্য সিস্টেম ফিচার স্ট্রিম করার জন্য আপনার <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চেয়ে অনুরোধ করছে"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"এই অ্যাপ, আপনার ফোন এবং <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string>
<string name="summary_generic" msgid="1761976003668044801">"এই অ্যাপ, আপনার ফোন এবং বেছে নেওয়া ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string>
<string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
<string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"বাতিল করুন"</string>
<string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বড় করুন"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> আড়াল করুন"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 2de0838..4c7ced2 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će biti dozvoljeni sinhroniziranje informacija, kao što je ime osobe koja upućuje poziv, interakcija s obavještenjima i pristup odobrenjima za Telefon, SMS, Kontakte, Kalendar, Zapisnike poziva i Uređaje u blizini."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aplikaciji će biti dozvoljeni sinhroniziranje informacija, kao što je ime osobe koja upućuje poziv i pristup ovim odobrenjima na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da postavite"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aplikaciji će biti dozvoljeni sinhroniziranje informacija, kao što je ime osobe koja upućuje poziv i pristup ovim odobrenjima na uređaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"naočale"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će biti dozvoljena interakcija s obavještenjima i pristup odobrenjima za Telefon, SMS, Kontakte, Mikrofon i Uređaje u blizini."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aplikaciji će biti dozvoljen pristup ovim odobrenjima na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aplikaciji će biti dozvoljen pristup ovim odobrenjima na uređaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije između vaših uređaja"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Dozvoliti uređaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da poduzme ovu radnju?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> traži odobrenje da prenosi aplikacije i druge funkcije sistema na uređajima u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i odabranog uređaja"</string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
<string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
<string name="permission_expand" msgid="893185038020887411">"Proširivanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Sužavanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 38a6dbc..17c912c 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Aquesta aplicació es necessita per gestionar el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per sincronitzar informació, com ara el nom d\'algú que truca, per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al calendari, als registres de trucades i als dispositius propers."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, i accedir a aquests permisos al dispositiu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Tria un dispositiu perquè el gestioni <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> per configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, i accedir a aquests permisos al dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ulleres"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Aquesta aplicació es necessita per gestionar el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al micròfon i als dispositius propers."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aquesta aplicació podrà accedir a aquests permisos del dispositiu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositiu"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aquesta aplicació podrà accedir a aquests permisos del dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) per reproduir en continu aplicacions entre els dispositius"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vols permetre que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dugui a terme aquesta acció?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sol·licita permís en nom del teu dispositiu (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) per reproduir en continu aplicacions i altres funcions del sistema en dispositius propers"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="summary_generic" msgid="1761976003668044801">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu triat"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
<string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel·la"</string>
<string name="consent_back" msgid="2560683030046918882">"Enrere"</string>
<string name="permission_expand" msgid="893185038020887411">"Desplega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Replega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 7151823..fe4d1af 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Vyberte <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci synchronizovat údaje, jako je jméno volajícího, interagovat s vašimi oznámeními a získat přístup k vašim oprávněním k telefonu, SMS, kontaktům, kalendáři, seznamům hovorů a zařízením v okolí."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, a získat přístup k těmto oprávněním v <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zařízení, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete nastavit"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, a získat na zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> přístup k těmto oprávněním"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovat zařízení <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"brýle"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s vašimi oznámeními a získat přístup k vašim oprávněním k telefonu, SMS, kontaktům, mikrofonu a zařízením v okolí."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Tato aplikace bude mít ve vašem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> povolený přístup k těmto oprávněním:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"zařízení"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Tato aplikace bude mít ve vašem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> povolený přístup k těmto oprávněním"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnění ke streamování aplikací mezi zařízeními"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Povolit zařízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> podniknout tuto akci?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem vašeho zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace a další systémové funkce do zařízení v okolí"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zařízením"</string>
<string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Zrušit"</string>
<string name="consent_back" msgid="2560683030046918882">"Zpět"</string>
<string name="permission_expand" msgid="893185038020887411">"Rozbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Sbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 14f2454..072a526 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Vælg det <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som skal administreres af <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og synkronisere oplysninger som f.eks. navnet på en person, der ringer, og appen får adgang til dine tilladelser for Opkald, Sms, Kalender, Opkaldshistorik og Enheder i nærheden."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Denne app får tilladelse til at synkronisere oplysninger, f.eks. navne på dem, der ringer, og adgang til disse tilladelser på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Vælg en enhed, som skal administreres af <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Vælg en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som du vil konfigurere"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Denne app får tilladelse til at synkronisere oplysninger, f.eks. navne på dem, der ringer, og adgang til disse tilladelser på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du tillade, at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrerer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"briller"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og tilgå tilladelserne Telefon, Sms, Kontakter, Mikrofon og Enheder i nærheden."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Denne app får adgang til disse tilladelser på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"enhed"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Denne app får adgang til disse tilladelser på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at streame apps mellem dine enheder"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du tillade, at <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> foretager denne handling?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps og andre systemfunktioner til enheder i nærheden"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og den valgte enhed"</string>
<string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Annuller"</string>
<string name="consent_back" msgid="2560683030046918882">"Tilbage"</string>
<string name="permission_expand" msgid="893185038020887411">"Udvid <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index d8c6ac3b..5a6a20d 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> auf das Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zugreifen darf?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Gerät „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string>
- <string name="summary_watch" msgid="898569637110705523">"Diese App wird zur Verwaltung deines Geräts (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf dann Daten wie den Namen eines Anrufers synchronisieren, mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“, „Kalender“, „Anruflisten“ und „Geräte in der Nähe“ zugreifen."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Diese App darf dann Daten wie den Namen eines Anrufers synchronisieren und auf folgende Berechtigungen auf deinem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> zugreifen"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Gerät auswählen, das von <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> verwaltet werden soll"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> zum Einrichten auswählen"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Diese App darf dann Daten wie den Namen eines Anrufers synchronisieren und auf diese Berechtigungen auf deinem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zugreifen"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> das Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> verwalten darf"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Glass-Geräte"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Diese App wird zur Verwaltung deines Geräts (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“, „Mikrofon“ und „Geräte in der Nähe“ zugreifen."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Diese App darf dann auf die folgenden Berechtigungen auf deinem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> zugreifen:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Diese App darf dann auf diese Berechtigungen auf deinem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zugreifen:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Darf das Gerät <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> diese Aktion ausführen?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein Gerät (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) um die Berechtigung, Apps und andere Systemfunktionen auf Geräte in der Nähe zu streamen"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und deinem Gerät (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) synchronisieren"</string>
<string name="summary_generic" msgid="1761976003668044801">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und dem ausgewählten Gerät synchronisieren"</string>
<string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
<string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Abbrechen"</string>
<string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> maximieren"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> minimieren"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 37fc39f..f7689af 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, να αλληλεπιδρά με τις ειδοποιήσεις σας και να αποκτά πρόσβαση στις άδειες Τηλέφωνο, SMS, Επαφές, Ημερολόγιο, Αρχεία καταγρ. κλήσ. και Συσκευές σε κοντινή απόσταση."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, και να αποκτά πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Επιλέξτε μια συσκευή για διαχείριση μέσω της εφαρμογής <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για ρύθμιση"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, και να αποκτά πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να διαχειρίζεται τη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ;"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"γυαλιά"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Θα επιτρέπεται στην εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> να αλληλεπιδρά με τις ειδοποιήσεις σας και να αποκτά πρόσβαση στις άδειες για το Τηλέφωνο, τα SMS, τις Επαφές, το Μικρόφωνο και τις Συσκευές σε κοντινή απόσταση."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Αυτή η εφαρμογή θα μπορεί να έχει πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"συσκευή"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Αυτή η εφαρμογή θα μπορεί να έχει πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στο <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> άδεια για ροή εφαρμογών μεταξύ των συσκευών σας"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Να επιτρέπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> να εκτελεί αυτήν την ενέργεια;"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για ροή εφαρμογών και άλλων λειτουργιών του συστήματος σε συσκευές σε κοντινή απόσταση"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, όπως το όνομα ενός ατόμου που σας καλεί."</string>
<string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της επιλεγμένης συσκευής σας, όπως το όνομα ενός ατόμου που σας καλεί."</string>
<string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
<string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Ακύρωση"</string>
<string name="consent_back" msgid="2560683030046918882">"Πίσω"</string>
<string name="permission_expand" msgid="893185038020887411">"Ανάπτυξη <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Σύμπτυξη <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index 2727d86..66a547d 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index cc221b4..843e479 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index 2727d86..66a547d 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index 2727d86..66a547d 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 431a69c..05b27b5c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don’t allow"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 26868f6..41d29bd 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
<string name="confirmation_title" msgid="4593465730772390351">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que la app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> lo administre"</string>
- <string name="summary_watch" msgid="898569637110705523">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá sincronizar información, como el nombre de la persona que llama, interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Calendario, Llamadas y Dispositivos cercanos."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Esta app podrá sincronizar información, como el nombre de alguien cuando te llame, y acceder a los siguientes permisos en tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lo administre"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Esta app podrá sincronizar información, como el nombre de alguien cuando te llame, y acceder a los siguientes permisos en tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Gafas"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta app es necesaria para administrar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Micrófono y Dispositivos cercanos."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Esta app podrá acceder a los siguientes permisos en tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Esta app podrá acceder a los siguientes permisos en tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para transmitir apps entre dispositivos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permites que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir apps y otras funciones del sistema a dispositivos cercanos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y el dispositivo elegido"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_expand" msgid="893185038020887411">"Expandir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index fedb8ae..9681de6 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
<string name="confirmation_title" msgid="4593465730772390351">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Se necesita esta aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá sincronizar información (por ejemplo, el nombre de la persona que te llama), interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, calendario, registros de llamadas y dispositivos cercanos."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Esta aplicación podrá sincronizar información, como el nombre de la persona que llama, y acceder a estos permisos de tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que lo gestione <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Elige el <xliff:g id="PROFILE_NAME">%1$s</xliff:g> que quieras configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Esta aplicación podrá sincronizar información, como el nombre de la persona que llama, y acceder a estos permisos de tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"gafas"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Se necesita esta aplicación para gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, micrófono y dispositivos cercanos."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Esta aplicación podrá acceder a estos permisos de tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Esta aplicación podrá acceder a estos permisos de tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para emitir aplicaciones en otros dispositivos tuyos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir aplicaciones y otras funciones del sistema en dispositivos cercanos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_expand" msgid="893185038020887411">"Desplegar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 29a04bc..e8c16e6 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Andke rakendusele <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> juurdepääs seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Seda rakendust on vaja teie seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse sünkroonida teavet, näiteks helistaja nime, kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide, kalendri, kõnelogide ja läheduses olevate seadmete lubadele."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Sellel rakendusel lubatakse sünkroonida teavet (nt helistaja nime) ja antakse need load teie seadmes <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Valige seade, mida haldab rakendus <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mis seadistada"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Sellel rakendusel lubatakse sünkroonida teavet (nt helistaja nime) ja antakse need load teie seadmes <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallata seadet <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"prillid"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Seda rakendust on vaja seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide, mikrofoni ja läheduses olevate seadmete lubadele."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Sellele rakendusele antakse need load teie seadmes <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Sellele rakendusele antakse need load teie seadmes <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Kas lubada seadmel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> teha seda toimingut?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada rakendusi ja muid süsteemi funktsioone läheduses olevatesse seadmetesse"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> vahel"</string>
<string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string>
<string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
<string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Tühista"</string>
<string name="consent_back" msgid="2560683030046918882">"Tagasi"</string>
<string name="permission_expand" msgid="893185038020887411">"Laienda: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Ahenda: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index a4f29e3..3bcca29 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> erabiltzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Aplikazioa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko behar da. Informazioa sinkronizatzeko (esate baterako, deitzaileen izenak), jakinarazpenekin interakzioan aritzeko, eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroak eta inguruko gailuak erabiltzeko baimena izango du <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>n informazioa sinkronizatu (esate baterako, deitzaileen izenak) eta baimen hauek erabili ahalko ditu aplikazioak"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Aukeratu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioak kudeatu behar duen gailua"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Aukeratu konfiguratu nahi duzun <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Informazioa sinkronizatu (esate baterako, deitzaileen izenak) eta baimen hauek erabili ahalko ditu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>n aplikazioak"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kudeatzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"betaurrekoak"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Aplikazioa \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" izeneko gailua kudeatzeko behar da. Jakinarazpenekin interakzioan aritzeko, eta telefonoa, SMSak, kontaktuak, mikrofonoa eta inguruko gailuak erabiltzeko baimena izango du <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>n baimen hauek erabili ahalko ditu aplikazioak:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"gailua"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Baimen hauek erabili ahalko ditu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>n aplikazioak:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu baterako baino gehiagotarako zerbitzuak"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ekintza hau gauzatzeko baimena eman nahi diozu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikazioak eta sistemaren beste eginbide batzuk inguruko gailuetara igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Telefonoaren eta <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string>
<string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string>
<string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
<string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Utzi"</string>
<string name="consent_back" msgid="2560683030046918882">"Atzera"</string>
<string name="permission_expand" msgid="893185038020887411">"Zabaldu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Tolestu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index d6c1a13..2adb4d8 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
<string name="confirmation_title" msgid="4593465730772390351">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود به <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی پیدا کند؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
- <string name="chooser_title" msgid="2262294130493605839">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. به <xliff:g id="APP_NAME">%2$s</xliff:g> اجازه داده میشود اطلاعاتی مثل نام شخصی را که تماس میگیرد همگامسازی کند، با اعلانهای شما تعامل داشته باشد، و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارشهای تماس»، و «دستگاههای اطراف» دسترسی داشته باشد."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"به این برنامه اجازه داده میشود اطلاعاتی مثل نام تماسگیرنده را همگامسازی کند و به این اجازهها در <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> شما دسترسی داشته باشد"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"انتخاب دستگاه برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای راهاندازی"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"به این برنامه اجازه داده میشود اطلاعاتی مثل نام تماسگیرنده را همگامسازی کند و به این اجازهها در <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما دسترسی داشته باشد"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> را مدیریت کند؟"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"عینک"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> لازم است. به <xliff:g id="APP_NAME">%2$s</xliff:g> اجازه داده میشود با اعلانهای شما تعامل داشته باشد و به اجازههای تلفنتان، پیامک، «مخاطبین»، «میکروفون»، و «دستگاههای اطراف» دسترسی داشته باشد."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"این برنامه مجاز میشود به این اجازهها در <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> شما دسترسی پیدا کند"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"دستگاه"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"این برنامه مجاز میشود به این اجازهها در <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما دسترسی پیدا کند"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"اجازه دادن به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای دسترسی به اطلاعات تلفن"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویسهای بیندستگاهی"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> اجازه میخواهد برنامهها را بین دستگاههای شما جاریسازی کند"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"به <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> اجازه داده شود این اقدام را انجام دهد؟"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه میخواهد تا برنامهها و دیگر ویژگیهای سیستم را در دستگاههای اطراف جاریسازی کند."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"این برنامه مجاز میشود اطلاعتی مثل نام شخصی را که تماس میگیرد بین تلفن شما و <xliff:g id="DEVICE_NAME">%1$s</xliff:g> همگامسازی کند"</string>
<string name="summary_generic" msgid="1761976003668044801">"این برنامه مجاز میشود اطلاعتی مثل نام شخصی را که تماس میگیرد بین تلفن شما و دستگاه انتخابشده همگامسازی کند"</string>
<string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string>
<string name="consent_no" msgid="2640796915611404382">"اجازه ندادن"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"لغو"</string>
<string name="consent_back" msgid="2560683030046918882">"برگشتن"</string>
<string name="permission_expand" msgid="893185038020887411">"ازهم بازکردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"جمع کردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 72122cb..11831b6 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Sallitaanko, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn laitteeseen: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> hallinnoi"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ylläpitoon (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan synkronoida tietoja (esimerkiksi soittajan nimen), hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, kalenteriin, puhelulokeihin ja lähellä olevat laitteet ‑lupiin."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Sovellus saa luvan synkronoida tietoja (esimerkiksi soittajan nimen) ja pääsyn näihin lupiin laitteella (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Valitse laite, jota <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallinnoi"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, niin voit suorittaa käyttöönoton"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Sovellus saa luvan synkronoida tietoja (esimerkiksi soittajan nimen) ja pääsyn näihin lupiin laitteella (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa ylläpitää laitetta: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"lasit"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Tätä sovellusta tarvitaan kohteen <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ylläpitoon. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, mikrofoniin ja lähellä olevat laitteet ‑lupiin."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Tämä sovellus saa käyttää näitä lupia laitteella (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"laite"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Tämä sovellus saa käyttää näitä lupia laitteella (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn näihin puhelimesi tietoihin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteidesi välillä"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Sallitko, että <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> voi suorittaa tämän toiminnon?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia ja muita järjestelmän ominaisuuksia lähellä oleviin laitteisiin."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja laitteen (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) välillä"</string>
<string name="summary_generic" msgid="1761976003668044801">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja valitun laitteen välillä"</string>
<string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
<string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Peruuta"</string>
<string name="consent_back" msgid="2560683030046918882">"Takaisin"</string>
<string name="permission_expand" msgid="893185038020887411">"Laajenna <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Tiivistä <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 6b3ed28..80f4f228 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Choisissez un(e) <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Cette application est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation de synchroniser des informations, comme le nom de l\'appelant, d\'interagir avec vos notifications et d\'accéder à vos autorisations pour le téléphone, les messages texte, les contacts, l\'agenda, les journaux d\'appels et les appareils à proximité."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Cette application sera autorisée à synchroniser des informations, comme le nom de l\'appelant, et à accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Choisir un appareil qui sera géré par <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choisir un appareil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pour le configurer"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Cette application sera autorisée à synchroniser des informations, comme le nom de l\'appelant, et à accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"lunettes"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Cette application est nécessaire pour gérer vos <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. L\'application <xliff:g id="APP_NAME">%2$s</xliff:g> sera autorisée à interagir avec vos notifications et à accéder à vos autorisations pour le téléphone, les messages texte, les contacts, le microphone et les appareils à proximité."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Cette application pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Cette application pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, de diffuser des applications et d\'autres fonctionnalités du système sur des appareils à proximité"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Cette application pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Cette application pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
<string name="consent_back" msgid="2560683030046918882">"Retour"</string>
<string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index b649f27..0469470 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Sélectionnez le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Cette appli est nécessaire pour gérer <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation de synchroniser des infos (comme le nom de l\'appelant), d\'interagir avec vos notifications et d\'accéder à votre téléphone, à votre agenda, ainsi qu\'à vos SMS, contacts, journaux d\'appels et appareils à proximité."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Cette appli sera autorisée à synchroniser des infos (comme le nom de l\'appelant) et disposera de ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Sélectionner l\'appareil qui sera géré par <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Sélectionner votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g> à configurer"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Cette appli sera autorisée à synchroniser des infos (comme le nom de l\'appelant) et disposera de ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"lunettes"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Cette appli est nécessaire pour gérer <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations du téléphone, des SMS, des contacts, du micro et des appareils à proximité."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Cette appli sera autorisée à accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Cette appli sera autorisée à accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour caster des applis d\'un appareil à l\'autre"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des applis et d\'autres fonctionnalités système en streaming sur des appareils à proximité"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et l\'appareil choisi"</string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
<string name="consent_back" msgid="2560683030046918882">"Retour"</string>
<string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index e7ff1e3..be232e9 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda ao dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Escolle un dispositivo (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Esta aplicación é necesaria para xestionar o teu dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá sincronizar información (por exemplo, o nome de quen chama), interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do calendario, dos rexistros de chamadas e dos dispositivos próximos."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) e acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolle un dispositivo para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Escolle o perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) que queiras configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) e acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> xestione o dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"lentes"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta aplicación é necesaria para xestionar o dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do micrófono e dos dispositivos próximos."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Esta aplicación poderá acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Esta aplicación poderá acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) para emitir contido de aplicacións entre os teus aparellos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Queres permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> leve a cabo esta acción?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir o contido das aplicacións e doutras funcións do sistema en dispositivos próximos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) entre o teléfono e o dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) entre o teléfono e o dispositivo escollido"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_expand" msgid="893185038020887411">"Despregar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 436d6cb..22b9d39 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
- <string name="summary_watch" msgid="898569637110705523">"તમારા <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ને મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને કૉલ કરનાર વ્યક્તિનું નામ જેવી માહિતી સિંક કરવાની, તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની અને તમારો ફોન, SMS, સંપર્કો, Calendar, કૉલ લૉગ તથા નજીકના ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"આ ઍપને, કૉલ કરનાર વ્યક્તિનું નામ જેવી માહિતી સિંક કરવાની અને તમારા <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ ડિવાઇસ પસંદ કરો"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"સેટઅપ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"આ ઍપને, કૉલ કરનાર વ્યક્તિનું નામ જેવી માહિતી સિંક કરવાની અને તમારા <xliff:g id="DEVICE_NAME">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> મેનેજ કરવા માટે મંજૂરી આપીએ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ચશ્માં"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ને મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની અને તમારો ફોન, SMS, સંપર્કો, માઇક્રોફોન તથા નજીકના ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"આ ઍપને તમારા <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી મળશે"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ડિવાઇસ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"આ ઍપને તમારા <xliff:g id="DEVICE_NAME">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી મળશે"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂરી આપો"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> વતી તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ને આ પગલું ભરવાની મંજૂરી આપીએ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> નજીકના ડિવાઇસ પર ઍપ અને સિસ્ટમની અન્ય સુવિધાઓ સ્ટ્રીમ કરવા તમારા <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"આ ઍપ તમારા ફોન અને <xliff:g id="DEVICE_NAME">%1$s</xliff:g> વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string>
<string name="summary_generic" msgid="1761976003668044801">"આ ઍપ તમારા ફોન અને પસંદ કરેલા ડિવાઇસ વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string>
<string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
<string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"રદ કરો"</string>
<string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને મોટું કરો"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને નાનું કરો"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index dd8e831..82eeecd 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string>
<string name="confirmation_title" msgid="4593465730772390351">"क्या <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> को ऐक्सेस करने के लिए <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अनुमति देनी है?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
- <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> की मदद से मैनेज किया जा सके"</string>
- <string name="summary_watch" msgid="898569637110705523">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> को मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> को डिवाइस की जानकारी सिंक करने की अनुमति होगी. जैसे, कॉल करने वाले व्यक्ति का नाम. इसे आपकी सूचनाओं पर कार्रवाई करने के साथ-साथ आपके फ़ोन, एसएमएस, संपर्कों, कैलेंडर, कॉल लॉग, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति भी होगी."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस करने के साथ-साथ कॉल करने वाले व्यक्ति के नाम जैसी जानकारी सिंक कर पाएगा"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> से मैनेज किया जाने वाला डिवाइस चुनें"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"सेट अप करने के लिए कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_NAME">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस करने के साथ-साथ कॉल करने वाले व्यक्ति के नाम जैसी जानकारी सिंक कर पाएगा"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"क्या <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> मैनेज करने की अनुमति देनी है?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"चश्मा"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> को डिवाइस की सूचनाओं पर कार्रवाई करने की अनुमति होगी. इसे आपके फ़ोन, मैसेज, संपर्कों, माइक्रोफ़ोन, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति भी होगी."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"डिवाइस"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_NAME">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> की ओर से, आपके डिवाइसों के बीच ऐप्लिकेशन स्ट्रीम करने की अनुमति मांग रहा है"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"क्या <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> को यह कार्रवाई करने की अनुमति देनी है?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, ऐप्लिकेशन और दूसरे सिस्टम की सुविधाओं को आस-पास मौजूद डिवाइसों पर स्ट्रीम करने की अनुमति मांग रहा है"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"यह ऐप्लिकेशन, आपके फ़ोन और <xliff:g id="DEVICE_NAME">%1$s</xliff:g> के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string>
<string name="summary_generic" msgid="1761976003668044801">"यह ऐप्लिकेशन, आपके फ़ोन और चुने हुए डिवाइस के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"रद्द करें"</string>
<string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> को बड़ा करें"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> को छोटा करें"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index d32a319..fc1a750 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Želite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će sinkronizirati podatke, primjerice ime pozivatelja, stupati u interakciju s vašim obavijestima i pristupati vašim dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aplikacija će moći sinkronizirati podatke kao što je ime pozivatelja i pristupiti tim dopuštenjima na vašem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite postaviti"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aplikacija će moći sinkronizirati podatke kao što je ime pozivatelja i pristupiti tim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"naočale"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta je aplikacija potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati vašim dopuštenjima za telefon, SMS-ove, kontakte, mikrofon i uređaje u blizini."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aplikacija će moći pristupati ovim dopuštenjima na vašem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aplikacija će moći pristupati ovim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za stream aplikacija s jednog uređaja na drugi"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Želite li uređaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dopustiti da izvrši tu radnju?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za emitiranje aplikacija i drugih značajki sustava na uređajima u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, primjerice ime pozivatelja"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i odabranog uređaja, primjerice ime pozivatelja"</string>
<string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Odustani"</string>
<string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
<string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Sažmi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 5943178..4f74486 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hozzáférését a következőhöz: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
- <string name="chooser_title" msgid="2262294130493605839">"A(z) <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
- <string name="summary_watch" msgid="898569637110705523">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> képes lesz szinkronizálni információkat (például a hívó fél nevét), műveleteket végezhet majd az értesítésekkel, és hozzáférhet majd a Telefon, az SMS, a Névjegyek, a Naptár, a Hívásnaplók és a Közeli eszközök engedélyekhez."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Ez az alkalmazás képes lesz szinkronizálni információkat (például a hívó fél nevét), és hozzáférhet majd ezekhez az engedélyekhez az Ön <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> eszközén"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazással kezelni kívánt eszköz kiválasztása"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Válassza ki a beállítani kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> nevet."</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Ez az alkalmazás képes lesz szinkronizálni információkat (például a hívó fél nevét), és hozzáférhet majd ezekhez az engedélyekhez az Ön <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközén"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Engedélyezi, hogy a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> kezelje a következő eszközt: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"szemüveg"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Erre az alkalmazásra szükség van a következő eszköz kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet majd a Telefon, az SMS, a Névjegyek, a Mikrofon és a Közeli eszközök engedélyekhez."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Az alkalmazás hozzáférhet majd ezekhez az engedélyekhez az Ön <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> eszközén"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"eszköz"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Az alkalmazás hozzáférhet majd ezekhez az engedélyekhez az Ön <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközén"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nevében az alkalmazások eszközök közötti streameléséhez"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Engedélyezi a(z) <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> számára ennek a műveletnek a végrehajtását?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások és más rendszerfunkciók közeli eszközökre történő streamelésére"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszköz között, mint például a hívó fél neve."</string>
<string name="summary_generic" msgid="1761976003668044801">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a kiválasztott eszköz között, mint például a hívó fél neve."</string>
<string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
<string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Mégse"</string>
<string name="consent_back" msgid="2560683030046918882">"Vissza"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> kibontása"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> összecsukása"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index 17f46ed..c6edd89 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> հավելվածի կողմից"</string>
- <string name="summary_watch" msgid="898569637110705523">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> պրոֆիլը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Օրացույց», «Կանչերի ցուցակ» և «Մոտակա սարքեր» թույլտվությունները։"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Այս հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, և կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ում"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Ընտրեք սարքը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածի միջոցով"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Կարգավորելու համար ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Այս հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, և կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ում"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ակնոց"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Այս հավելվածն անհրաժեշտ է <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Խոսափող» և «Մոտակա սարքեր» թույլտվությունները։"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Այս հավելվածը կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ում"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"սարք"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Այս հավելվածը կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ում"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Թույլատրե՞լ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> հավելվածին կատարել այս գործողությունը"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ մոտակա սարքերին հավելվածներ և համակարգի այլ գործառույթներ հեռարձակելու համար"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքի տվյալները, օր․՝ զանգողի անունը"</string>
<string name="summary_generic" msgid="1761976003668044801">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և ընտրված սարքի տվյալները, օր․՝ զանգողի անունը"</string>
<string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
<string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Չեղարկել"</string>
<string name="consent_back" msgid="2560683030046918882">"Հետ"</string>
<string name="permission_expand" msgid="893185038020887411">"Ծավալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Ծալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index ec736197..837fa0c 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan menyinkronkan info, seperti nama penelepon, berinteraksi dengan notifikasi, dan mengakses izin Telepon, SMS, Kontak, Kalender, Log panggilan, dan Perangkat di sekitar."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aplikasi ini akan diizinkan menyinkronkan info, seperti nama penelepon, dan mengakses izin ini di <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> Anda"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih perangkat untuk dikelola oleh <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disiapkan"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aplikasi ini akan diizinkan menyinkronkan info, seperti nama penelepon, dan mengakses izin ini di <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Anda"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengelola <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"kacamata pintar"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Ponsel, SMS, Kontak, Mikrofon, dan Perangkat di sekitar."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aplikasi ini akan diizinkan mengakses izin ini di <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> Anda"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"perangkat"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aplikasi ini akan diizinkan mengakses izin ini di <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan tindakan ini?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstreaming aplikasi dan fitur sistem lainnya ke perangkat di sekitar"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string>
<string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Batalkan"</string>
<string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
<string name="permission_expand" msgid="893185038020887411">"Luaskan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Ciutkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 3f55d5d..283d0e6 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> á að stjórna"</string>
- <string name="summary_watch" msgid="898569637110705523">"Þetta forrit er nauðsynlegt til að stjórna <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær heimild til að samstilla upplýsingar, t.d. nafn þess sem hringir, og bregðast við tilkynningum og fær aðgang að heimildum fyrir síma, SMS, tengiliði, dagatal, símtalaskrár og nálæg tæki."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Þetta forrit fær heimild til að samstilla upplýsingar, t.d. nafn þess sem hringir, og fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Veldu tæki sem <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> á að stjórna"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Veldu <xliff:g id="PROFILE_NAME">%1$s</xliff:g> til að setja upp"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Þetta forrit fær heimild til að samstilla upplýsingar, t.d. nafn þess sem hringir, og fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að stjórna <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"gleraugu"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Þetta forrit er nauðsynlegt til að stjórna <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær heimild til að bregðast við tilkynningum og fær aðgang að heimildum fyrir síma, SMS, tengiliði, hljóðnema og nálæg tæki."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Þetta forrit fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"tæki"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Þetta forrit fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til að streyma forritum á milli tækjanna þinna"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leyfa <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> að framkvæma þessa aðgerð?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum og öðrum kerfiseiginleikum í nálægum tækjum"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og valins tækis"</string>
<string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
<string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Hætta við"</string>
<string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
<string name="permission_expand" msgid="893185038020887411">"Stækka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Minnka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 9f7679b..dfbd2f5 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da gestire con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà sincronizzare informazioni, ad esempio il nome di un chiamante, interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Calendario, Registri chiamate e Dispositivi nelle vicinanze."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, e accedere alle seguenti autorizzazioni su <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>:"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Scegli un dispositivo che sia gestito da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da configurare"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, e accedere alle seguenti autorizzazioni su <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di gestire <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"occhiali"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Microfono e Dispositivi nelle vicinanze."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Questa app potrà accedere alle seguenti autorizzazioni su <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Questa app potrà accedere alle seguenti autorizzazioni su <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> l\'autorizzazione a trasmettere app in streaming tra i dispositivi"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vuoi consentire a <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> di compiere questa azione?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione a trasmettere in streaming app e altre funzionalità di sistema ai dispositivi nelle vicinanze"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string>
<string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
<string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Annulla"</string>
<string name="consent_back" msgid="2560683030046918882">"Indietro"</string>
<string name="permission_expand" msgid="893185038020887411">"Espandi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Comprimi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 573b8a7..13e514c 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
<string name="confirmation_title" msgid="4593465730772390351">"לאשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&g; לגשת אל <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
- <string name="chooser_title" msgid="2262294130493605839">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, לבצע פעולות בהתראות ולקבל הרשאות גישה לטלפון, ל-SMS, לאנשי הקשר, ליומן, ליומני השיחות ולמכשירים בקרבת מקום."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, ולגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"בחירה של מכשיר לניהול באמצעות <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> להגדרה"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, ולגשת להרשאות האלה ב<xliff:g id="DEVICE_NAME">%1$s</xliff:g> שלך"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"מתן הרשאה לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&g; לנהל את <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"משקפיים"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"האפליקציה הזו נחוצה כדי לנהל את \'<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\'. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS, לאנשי הקשר, למיקרופון ולמכשירים בקרבת מקום."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"האפליקציה הזו תוכל לגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"מכשיר"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"האפליקציה הזו תוכל לגשת להרשאות האלה ב<xliff:g id="DEVICE_NAME">%1$s</xliff:g> שלך"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור המכשיר <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> כדי לשדר אפליקציות בין המכשירים שלך"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"לתת הרשאה למכשיר <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> לבצע את הפעולה הזו?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור <xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי להעביר אפליקציות ותכונות מערכת אחרות בסטרימינג למכשירים בקרבת מקום"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר שבחרת"</string>
<string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
<string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ביטול"</string>
<string name="consent_back" msgid="2560683030046918882">"חזרה"</string>
<string name="permission_expand" msgid="893185038020887411">"הרחבה של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"כיווץ של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 0439d5f1..4ddef24 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャー"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> へのアクセスを許可しますか?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
- <string name="summary_watch" msgid="898569637110705523">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は通話相手の名前などの情報を同期したり、デバイスの通知を使用したり、電話、SMS、連絡先、カレンダー、通話履歴、付近のデバイスの権限にアクセスしたりできるようになります。"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"このアプリは、通話相手の名前などの情報を同期したり、<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>の以下の権限にアクセスしたりできるようになります"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> の管理対象となるデバイスの選択"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"設定する<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"このアプリは、通話相手の名前などの情報を同期したり、<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の以下の権限にアクセスしたりできるようになります"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> の管理を許可しますか?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"このアプリは <xliff:g id="DEVICE_NAME">%1$s</xliff:g> の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> はデバイスの通知を使用したり、電話、SMS、連絡先、マイク、付近のデバイスの権限にアクセスしたりできるようになります。"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"このアプリは、<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>の以下の権限にアクセスできるようになります"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"デバイス"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"このアプリは、<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の以下の権限にアクセスできるようになります"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> に代わってデバイス間でアプリをストリーミングする権限をリクエストしています"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> にこの操作の実行を許可しますか?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリやその他のシステム機能を付近のデバイスにストリーミングする権限をリクエストしています"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"このアプリは、あなたのスマートフォンと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> との間で、通話相手の名前などの情報を同期できるようになります"</string>
<string name="summary_generic" msgid="1761976003668044801">"このアプリは、あなたのスマートフォンと選択したデバイスとの間で、通話相手の名前などの情報を同期できるようになります"</string>
<string name="consent_yes" msgid="8344487259618762872">"許可"</string>
<string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"キャンセル"</string>
<string name="consent_back" msgid="2560683030046918882">"戻る"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>を開く"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>を閉じる"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index e62afad..995b4e7 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
<string name="confirmation_title" msgid="4593465730772390351">"მიანიჭებთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> მოწყობილობაზე წვდომას?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
- <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-მა"</string>
- <string name="summary_watch" msgid="898569637110705523">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g>-ს ექნება ისეთი ინფორმაციის სინქრონიზაციის უფლება, როგორიც იმ ადამიანის სახელია, რომელიც გირეკავთ; ასევე, თქვენს შეტყობინებებთან ინტერაქციისა და თქვენს ტელეფონზე, SMS-ებზე, კონტაქტებზე, კალენდარზე, ზარების ჟურნალებსა და ახლომახლო მოწყობილობების ნებართვებზე წვდომის უფლება."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას (მაგალითად, იმ ადამიანის სახელი, რომელიც გირეკავთ) და ამ წვდომებზე უფლების მოპოვებას თქვენს <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ში"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"აირჩიეთ მოწყობილობა, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპმა"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> დასაყენებლად"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ეს აპი შეძლებს, დაასინქრონოს ინფორმაცია, მაგალითად, შემომავალი ზარის ავტორის სახელი და წვდომა იქონიოს ამ ნებართვებზე თქვენს <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ში"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ნება დართეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</strong> მართოს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"სათვალე"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ის სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენს ტელეფონზე, SMS-ებზე, კონტაქტებზე, მიკროფონსა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ეს აპი შეძლებს ამ ნებართვებზე წვდომას თქვენს <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ში"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"მოწყობილობა"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ეს აპი შეძლებს ამ ნებართვებზე წვდომას თქვენს <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ში"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-ის სახელით, რომ მოწყობილობებს შორის სტრიმინგი შეძლოს"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"გსურთ ნება მისცეთ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს</strong> ამ მოქმედების შესასრულებლად?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს თქვენი <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით აპების და სისტემის სხვა ფუნქციების ახლომახლო მოწყობილობებზე სტრიმინგის ნებართვას"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string>
<string name="summary_generic" msgid="1761976003668044801">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ მოწყობილობას შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string>
<string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
<string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"გაუქმება"</string>
<string name="consent_back" msgid="2560683030046918882">"უკან"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის გაფართოება"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის ჩაკეცვა"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 92951cb..0330d96 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын пайдалануға рұқсат беру керек пе?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
- <string name="summary_watch" msgid="898569637110705523">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы қоңырау шалушының аты сияқты деректі синхрондау, хабарландыруларды оқу және телефон, SMS, контактілер, күнтізбе, қоңырау журналдары мен маңайдағы құрылғылар рұқсаттарын пайдалана алады."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Бұл қолданба қоңырау шалушының аты сияқты деректі синхрондай алады және <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> құрылғысындағы мына рұқсаттарды пайдалана алады."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> арқылы басқарылатын құрылғыны таңдаңыз"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Реттеу үшін <xliff:g id="PROFILE_NAME">%1$s</xliff:g> таңдаңыз"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Бұл қолданба қоңырау шалушының аты сияқты деректі синхрондай алады және <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысындағы мына рұқсаттарды пайдалана алады."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын басқаруға рұқсат беру керек пе?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"көзілдірік"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына хабарландыруларды оқуға, телефонды, хабарларды, контактілерді, микрофон мен маңайдағы құрылғыларды пайдалануға рұқсат беріледі."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Бұл қолданба <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> құрылғысында осы рұқсаттарды пайдалана алады."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"құрылғы"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысында осы рұқсаттарды пайдалана алады."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> атынан құрылғылар арасында қолданбалар трансляциялау үшін рұқсат сұрайды."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> құрылғысына бұл әрекетті орындауға рұқсат беру керек пе?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан қолданбалар мен басқа да жүйе функцияларын маңайдағы құрылғыларға трансляциялау рұқсатын сұрап тұр."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Бұл қолданба телефон мен <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string>
<string name="summary_generic" msgid="1761976003668044801">"Бұл қолданба телефон мен таңдалған құрылғы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string>
<string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
<string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Бас тарту"</string>
<string name="consent_back" msgid="2560683030046918882">"Артқа"</string>
<string name="permission_expand" msgid="893185038020887411">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жаю"</string>
<string name="permission_collapse" msgid="3320833884220844084">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жию"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 18bd88c..e9ca811 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"កម្មវិធីគ្រប់គ្រងឧបករណ៍ដៃគូ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
- <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម ធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតទូរសព្ទ, SMS, ទំនាក់ទំនង, ប្រតិទិន, កំណត់ហេតុហៅទូរសព្ទ និងឧបករណ៍នៅជិតរបស់អ្នក។"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"កម្មវិធីនេះនឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម និងចូលប្រើការអនុញ្ញាតទាំងនេះនៅលើ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> របស់អ្នក"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"ជ្រើសរើសឧបករណ៍ ដើម្បីដាក់ក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីរៀបចំ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"កម្មវិធីនេះនឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម និងចូលប្រើប្រាស់ការអនុញ្ញាតទាំងនេះនៅលើ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> គ្រប់គ្រង <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"វ៉ែនតា"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g>។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតរបស់ទូរសព្ទ, SMS, ទំនាក់ទំនង, មីក្រូហ្វូន និងឧបករណ៍នៅជិតរបស់អ្នក។"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"កម្មវិធីនេះនឹងត្រូវបានអនុញ្ញាតឱ្យចូលប្រើការអនុញ្ញាតទាំងនេះនៅលើ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> របស់អ្នក"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ឧបករណ៍"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"កម្មវិធីនេះនឹងត្រូវបានអនុញ្ញាតឱ្យចូលប្រើប្រាស់ការអនុញ្ញាតទាំងនេះនៅលើ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីបញ្ចាំងកម្មវិធីរវាងឧបករណ៍របស់អ្នក"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"អនុញ្ញាតឱ្យ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ធ្វើសកម្មភាពនេះឬ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីចាក់ផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធផ្សេងទៀតទៅកាន់ឧបករណ៍នៅជិត"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"កម្មវិធីនេះនឹងអាចធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម រវាង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> និងទូរសព្ទរបស់អ្នក"</string>
<string name="summary_generic" msgid="1761976003668044801">"កម្មវិធីនេះនឹងអាចធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម រវាងឧបករណ៍ដែលបានជ្រើសរើស និងទូរសព្ទរបស់អ្នក"</string>
<string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
<string name="consent_no" msgid="2640796915611404382">"មិនអនុញ្ញាត"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"បោះបង់"</string>
<string name="consent_back" msgid="2560683030046918882">"ថយក្រោយ"</string>
<string name="permission_expand" msgid="893185038020887411">"ពង្រីក <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"បង្រួម <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 1080b63..0643336 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="summary_watch" msgid="898569637110705523">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್ನ ಅಗತ್ಯವಿದೆ. ಕರೆ ಮಾಡುವವರ ಹೆಸರು, ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, ಕ್ಯಾಲೆಂಡರ್, ಕರೆಯ ಲಾಗ್ಗಳು ಮತ್ತು ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ದೃಢೀಕರಣಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಮತ್ತು ಈ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ ಸಾಧನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ಸೆಟಪ್ ಮಾಡಲು <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆರಿಸಿ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಮತ್ತು ಈ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ನಲ್ಲಿ ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? ನಿರ್ವಹಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ಗ್ಲಾಸ್ಗಳು"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್ನ ಅಗತ್ಯವಿದೆ. <xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ ಈ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ಸಾಧನ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ನಲ್ಲಿ ಈ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಡಿವೈಸ್ ಸೇವೆಗಳು"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ಈ ಆ್ಯಕ್ಷನ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ಅನುಮತಿಸಬೇಕೇ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳಿಗೆ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಇತರ ಸಿಸ್ಟಂ ಫೀಚರ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ರ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string>
<string name="summary_generic" msgid="1761976003668044801">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು ಆಯ್ಕೆಮಾಡಿದ ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string>
<string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
<string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ರದ್ದುಮಾಡಿ"</string>
<string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ವಿಸ್ತರಿಸಿ"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 8128d8a..727b766 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 액세스하도록 허용하시겠습니까?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>를 선택"</string>
- <string name="summary_watch" msgid="898569637110705523">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 정보(예: 발신자 이름)를 동기화하고, 알림과 상호작용하고, 전화, SMS, 연락처, 캘린더, 통화 기록 및 근처 기기에 액세스할 수 있게 됩니다."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"이 앱이 정보(예: 발신자 이름)를 동기화하고 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 관리할 기기 선택"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"설정할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 선택"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"이 앱이 정보(예: 발신자 이름)를 동기화하고 <xliff:g id="DEVICE_NAME">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? 기기를 관리하도록 허용"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"안경"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, 마이크, 근처 기기에 대한 권한을 갖게 됩니다."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"앱이 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"기기"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"앱이 <xliff:g id="DEVICE_NAME">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>이 휴대전화의 이 정보에 액세스하도록 허용합니다."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> 기기가 이 작업을 수행하도록 허용하시겠습니까?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 근처 기기로 앱 및 기타 시스템 기능을 스트리밍할 권한을 요청하고 있습니다."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"이 앱에서 휴대전화와 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string>
<string name="summary_generic" msgid="1761976003668044801">"이 앱에서 휴대전화와 선택한 기기 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string>
<string name="consent_yes" msgid="8344487259618762872">"허용"</string>
<string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"취소"</string>
<string name="consent_back" msgid="2560683030046918882">"뒤로"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 펼치기"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 접기"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 568a1739..c5f3d21 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүнө кирүүгө уруксат бересизби?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> тарабынан башкарылсын"</string>
- <string name="summary_watch" msgid="898569637110705523">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> маалыматты шайкештирип, мисалы, билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, байланыштар, жылнаама, чалуулар тизмеси жана жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Бул колдонмого маалыматты, мисалы, чалып жаткан адамдын аты-жөнүн шайкештирүүгө жана <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> аркылуу башкарыла турган түзмөктү тандаңыз"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Тууралоо үчүн <xliff:g id="PROFILE_NAME">%1$s</xliff:g> тандаңыз"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Бул колдонмого маалыматты, мисалы, чалып жаткан адамдын аты-жөнүн шайкештирүүгө жана <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүн тескөөгө уруксат бересизби?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"көз айнектер"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүн башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, Байланыштар, Микрофон жана Жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Бул колдонмого <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"түзмөк"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Бул колдонмого <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрүңүздүн ортосунда колдонмолорду алып ойнотууга уруксат сурап жатат"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> түзмөгүнө бул аракетти аткарууга уруксат бересизби?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан жакын жердеги түзмөктөрдө колдонмолорду жана системанын башка функцияларын алып ойнотууга уруксат сурап жатат"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгү менен шайкештирет"</string>
<string name="summary_generic" msgid="1761976003668044801">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана тандалган түзмөк менен шайкештирет"</string>
<string name="consent_yes" msgid="8344487259618762872">"Ооба"</string>
<string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Жокко чыгаруу"</string>
<string name="consent_back" msgid="2560683030046918882">"Артка"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жайып көрсөтүү"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жыйыштыруу"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 08ea7a9..bdb5fd9 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ການໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ສິດເຂົ້າເຖິງໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ປະຕິທິນ, ບັນທຶກການໂທ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ແອັບນີ້ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ຊິ້ງຂໍ້ມູນ, ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ ແລະ ສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ຂອງທ່ານ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"ເລືອກອຸປະກອນທີ່ຈະໃຫ້ມີການຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ທີ່ຈະຕັ້ງຄ່າ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ແອັບນີ້ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ຊິ້ງຂໍ້ມູນ, ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ ແລະ ສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ຈັດການ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ແວ່ນຕາ"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ການອະນຸຍາດສິດເຂົ້າເຖິງໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ໄມໂຄຣໂຟນ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ແອັບນີ້ຈະໄດ້ຮັບສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ຂອງທ່ານ"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ອຸປະກອນ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ແອັບນີ້ຈະໄດ້ຮັບສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຕ່າງໆຂອງທ່ານ"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ອະນຸຍາດ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ເພື່ອດຳເນີນຄຳສັ່ງນີ້ບໍ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກໍາລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ຂອງທ່ານເພື່ອສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດລະບົບອື່ນໆໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ໄດ້"</string>
<string name="summary_generic" msgid="1761976003668044801">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ ອຸປະກອນທີ່ເລືອກໄວ້ໄດ້"</string>
<string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
<string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ຍົກເລີກ"</string>
<string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string>
<string name="permission_expand" msgid="893185038020887411">"ຂະຫຍາຍ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"ຫຍໍ້ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ລົງ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 0a800ee..a32d5b4 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> (pasirinkite)"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ši programa reikalinga norint tvarkyti jūsų įrenginį „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. Programai „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, sąveikauti su jūsų pranešimais ir pasiekti jūsų leidimus „Telefonas“, „SMS“, „Kontaktai“, „Kalendorius“, „Skambučių žurnalai“ ir „Įrenginiai netoliese."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Šiai programai bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, ir pasiekti toliau nurodytus leidimus jūsų <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Įrenginio, kuris bus valdomas naudojant programą <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, pasirinkimas"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Norimo nustatyti <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pasirinkimas"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Šiai programai bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, ir pasiekti toliau nurodytus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> leidimus"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> valdyti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"akiniai"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ši programa reikalinga norint tvarkyti įrenginį „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. Programai „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su jūsų pranešimais ir pasiekti jūsų leidimus „Telefonas“, „SMS“, „Kontaktai“, „Mikrofonas“ ir „Įrenginiai netoliese“."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Šiai programai bus leidžiama pasiekti toliau nurodytus leidimus jūsų <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"įrenginio"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Šiai programai bus leidžiama pasiekti toliau nurodytus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> leidimus."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš vieno įrenginio į kitą"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leisti <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> atlikti šį veiksmą?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas ir kitas sistemos funkcijas įrenginiams netoliese"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir įrenginiu „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir pasirinktu įrenginiu"</string>
<string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
<string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Atšaukti"</string>
<string name="consent_back" msgid="2560683030046918882">"Atgal"</string>
<string name="permission_expand" msgid="893185038020887411">"Išskleisti „<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>“"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Sutraukti „<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>“"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 43dedbd..94d573e 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. <xliff:g id="APP_NAME">%2$s</xliff:g> drīkstēs sinhronizēt informāciju (piemēram, zvanītāja vārdu), mijiedarboties ar jūsu paziņojumiem un piekļūt atļaujām Tālrunis, Īsziņas, Kontaktpersonas, Kalendārs, Zvanu žurnāli un Tuvumā esošas ierīces."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Šī lietotne drīkstēs sinhronizēt informāciju, piemēram, zvanītāja vārdu, un piekļūt norādītajām atļaujām jūsu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Izvēlieties ierīci, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Jāizvēlas <xliff:g id="PROFILE_NAME">%1$s</xliff:g> iestatīšanai"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Šī lietotne drīkstēs sinhronizēt informāciju, piemēram, zvanītāja vārdu, un piekļūt norādītajām atļaujām jūsu ierīcē (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"brilles"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Šī lietotne ir nepieciešama šādas ierīces pārvaldībai: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> drīkstēs mijiedarboties ar jūsu paziņojumiem un piekļūt atļaujām Tālrunis, Īsziņas, Kontaktpersonas, Mikrofons un Tuvumā esošas ierīces."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Šai lietotnei tiks sniegta piekļuve norādītajām atļaujām jūsu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ierīce"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Šai lietotnei tiks sniegta piekļuve norādītajām atļaujām jūsu ierīcē (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt lietotnes starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vai atļaut ierīcei <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> veikt šo darbību?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju tuvumā esošās ierīcēs straumēt lietotnes un citas sistēmas funkcijas šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un šo ierīci: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un izvēlēto ierīci"</string>
<string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
<string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Atcelt"</string>
<string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string>
<string name="permission_expand" msgid="893185038020887411">"Izvērst: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Sakļaut: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 7d053a7..249b3c9 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Ќе дозволите <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Апликацијава е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да ги синхронизира податоците како што се имињата на јавувачите, да остварува интеракција со известувањата и да пристапува до дозволите за „Телефон“, SMS, „Контакти“, „Календар“, „Евиденција на повици“ и „Уреди во близина“."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Оваа апликација ќе има дозвола да ги синхронизира податоците како што се имињата на јавувачите и да пристапува до следниве дозволи на вашиот <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете уред со којшто ќе управува <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> за поставување"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Апликацијава ќе има дозвола да ги синхронизира податоците како што се имињата на јавувачите и да пристапува до следниве дозволи на вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Ќе дозволите <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управува со <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"очила"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Апликацијава е потребна за управување со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за „Телефон“, SMS, „Контакти“, „Микрофон“ и „Уреди во близина“."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Апликацијава ќе може да пристапува до овие дозволи на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"уред"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Апликацијава ќе може да пристапува до овие дозволи на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Овозможете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до овие податоци на телефонот"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за да стримува апликации помеѓу вашите уреди"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ќе дозволите <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> да го преземе ова дејство?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да стримува апликации и други системски функции на уредите во близина"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и избраниот уред"</string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Собери <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 21dcfa1..a408b65 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
- <string name="summary_watch" msgid="898569637110705523">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ സമന്വയിപ്പിക്കുന്നതിനും നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, Contacts, Calendar, കോൾ ചരിത്രം, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> ആപ്പിനെ അനുവദിക്കും."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ സമന്വയിപ്പിക്കാനും നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> എന്നതിൽ ഈ അനുമതികൾ ആക്സസ് ചെയ്യാനും ഈ ആപ്പിനെ അനുവദിക്കും"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു ഉപകരണം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"സജ്ജീകരിക്കാൻ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ സമന്വയിപ്പിക്കാനും നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിൽ ഈ അനുമതികൾ ആക്സസ് ചെയ്യാനും ഈ ആപ്പിനെ അനുവദിക്കും"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? മാനേജ് ചെയ്യാൻ, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ഗ്ലാസുകൾ"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. നിങ്ങളുടെ അറിയിപ്പുകളുമായി ഇടപഴകാനും ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, മൈക്രോഫോൺ, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> എന്നതിൽ ഇനിപ്പറയുന്ന അനുമതികൾ ആക്സസ് ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കും"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ഉപകരണം"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിൽ ഇനിപ്പറയുന്ന അനുമതികൾ ആക്സസ് ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കും"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> എന്ന ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നത് അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ഈ പ്രവർത്തനം നടത്താൻ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"സമീപമുള്ള ഉപകരണങ്ങളിൽ ആപ്പുകളും മറ്റ് സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string>
<string name="summary_generic" msgid="1761976003668044801">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും തിരഞ്ഞെടുത്ത ഉപകരണത്തിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string>
<string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
<string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"റദ്ദാക്കുക"</string>
<string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> വികസിപ്പിക്കുക"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ചുരുക്കുക"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 0c31abf..4464c05 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-д <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д хандахыг зөвшөөрөх үү?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
- <string name="summary_watch" msgid="898569637110705523">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д залгаж буй хүний нэр зэрэг мэдээллийг синк хийх, таны мэдэгдэлтэй харилцан үйлдэл хийх, Утас, SMS, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Энэ аппад залгаж буй хүний нэр зэрэг мэдээллийг синк хийх болон таны <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-н эдгээр зөвшөөрөлд хандахыг зөвшөөрнө"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-н удирдах төхөөрөмжийг сонгоно уу"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Тохируулахын тулд <xliff:g id="PROFILE_NAME">%1$s</xliff:g> сонгоно уу"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Энэ аппад залгаж буй хүний нэр зэрэг мэдээллийг синк хийх болон таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-н эдгээр зөвшөөрөлд хандахыг зөвшөөрнө"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г удирдахыг зөвшөөрөх үү?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"нүдний шил"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Энэ апп <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д таны мэдэгдэлтэй харилцан үйлдэл хийх, Утас, SMS, Харилцагчид, Микрофон болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Энэ апп таны <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-н эдгээр зөвшөөрөлд хандах эрхтэй байх болно"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"төхөөрөмж"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-н эдгээр зөвшөөрөлд хандах эрхтэй байх болно"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Таны төхөөрөмжүүд хооронд апп дамжуулахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-д энэ үйлдлийг хийхийг зөвшөөрөх үү?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс аппууд болон системийн бусад онцлогийг ойролцоох төхөөрөмжүүд рүү дамжуулах зөвшөөрөл хүсэж байна"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-н хооронд синк хийх боломжтой болно"</string>
<string name="summary_generic" msgid="1761976003668044801">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон сонгосон төхөөрөмжийн хооронд синк хийх боломжтой болно"</string>
<string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
<string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Цуцлах"</string>
<string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г дэлгэх"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г хураах"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index b94cfac..ee699d5 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> अॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
- <string name="summary_watch" msgid="898569637110705523">"तुमचे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करण्याची, तुमच्या सूचनांसोबत संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क, कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"या अॅपला कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करण्याची आणि तुमच्या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> वर पुढील परवानग्या अॅक्सेस करण्याची अनुमती दिली जाईल"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी डिव्हाइस निवडा"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"सेट करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"या अॅपला कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करण्याची आणि तुमच्या <xliff:g id="DEVICE_NAME">%1$s</xliff:g> वर या परवानग्या अॅक्सेस करण्याची अनुमती असेल"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापित करण्याची अनुमती द्यायची आहे?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांसोबत संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क, मायक्रोफोन व जवळपासच्या डिव्हाइसच्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"या अॅपला तुमच्या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> वर या परवानग्या अॅक्सेस करण्याची अनुमती दिली जाईल"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"डिव्हाइस"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"या अॅपला तुमच्या <xliff:g id="DEVICE_NAME">%1$s</xliff:g> वर या परवानग्या अॅक्सेस करण्याची अनुमती असेल"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला ही माहिती तुमच्या फोनवरून अॅक्सेस करण्यासाठी अनुमती द्या"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"तुमच्या डिव्हाइसदरम्यान ॲप्स स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ला ही कृती करण्याची अनुमती द्यायची आहे का?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे जवळपासच्या डिव्हाइसवर अॅप्स आणि इतर सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी तुमच्या <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करा"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"हे ॲप तुमचा फोन आणि <xliff:g id="DEVICE_NAME">%1$s</xliff:g> दरम्यान कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string>
<string name="summary_generic" msgid="1761976003668044801">"हे ॲप तुमचा फोन आणि निवडलेल्या डिव्हाइसदरम्यान कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"रद्द करा"</string>
<string name="consent_back" msgid="2560683030046918882">"मागे जा"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> चा विस्तार करा"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोलॅप्स करा"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 93745c8..04837ff 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan untuk menyegerakkan maklumat seperti nama individu yang memanggil, berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Kalendar, Log panggilan dan Peranti berdekatan anda."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Apl ini akan dibenarkan untuk menyegerakkan maklumat seperti nama seseorang yang membuat panggilan dan mengakses kebenaran ini pada <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> anda"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih peranti untuk diurus oleh <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disediakan"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Apl ini akan dibenarkan untuk menyegerakkan maklumat seperti nama individu yang membuat panggilan dan mengakses kebenaran ini pada <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengurus <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"cermin mata"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan untuk berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Mikrofon dan Peranti berdekatan anda."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Apl ini akan dibenarkan untuk mengakses kebenaran yang berikut pada <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> anda"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"peranti"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Apl ini akan dibenarkan untuk mengakses kebenaran yang berikut pada <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses maklumat ini daripada telefon anda"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Benarkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> mengambil tindakan ini?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk menstrim apl dan ciri sistem yang lain pada peranti berdekatan"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan peranti yang dipilih"</string>
<string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Batal"</string>
<string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
<string name="permission_expand" msgid="893185038020887411">"Kembangkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Kuncupkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 3f298a0..9c7048b 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? သုံးခွင့်ပြုခြင်း"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
- <string name="summary_watch" msgid="898569637110705523">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်ရန်၊ သင်၏ဖုန်း၊ SMS စာတိုစနစ်၊ အဆက်အသွယ်များ၊ ပြက္ခဒိန်၊ ခေါ်ဆိုမှတ်တမ်းနှင့် အနီးတစ်ဝိုက်ရှိ စက်များဆိုင်ရာ ခွင့်ပြုချက်များသုံးရန်၊ အကြောင်းကြားချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်။"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်ရန်နှင့် သင့် <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> က စီမံခန့်ခွဲရန် စက်တစ်ခုကို ရွေးပါ"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"စနစ်ထည့်သွင်းရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးပါ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်ရန်နှင့် သင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား စီမံခွင့်ပြုမလား။"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"မျက်မှန်"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ သင်၏ဖုန်း၊ SMS စာတိုစနစ်၊ အဆက်အသွယ်များ၊ မိုက်ခရိုဖုန်းနှင့် အနီးတစ်ဝိုက်ရှိ စက်များဆိုင်ရာ ခွင့်ပြုချက်များသုံးရန်၊ အကြောင်းကြားချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်။"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"သင့် <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"စက်"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"သင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင်၏စက်များအကြား အက်ပ်များတိုက်ရိုက်လွှင့်ရန် <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ကို ဤသို့လုပ်ဆောင်ခွင့်ပြုမလား။"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အနီးတစ်ဝိုက်ရှိ အက်ပ်များနှင့် အခြားစနစ်အင်္ဂါရပ်များကို တိုက်ရိုက်ဖွင့်ရန် သင့် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string>
<string name="summary_generic" msgid="1761976003668044801">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် ရွေးထားသောစက်အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string>
<string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
<string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"မလုပ်တော့"</string>
<string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို ပိုပြရန်"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို လျှော့ပြရန်"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 2c794d9..8ecaeba 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å synkronisere informasjon som navnet til noen som ringer, og samhandle med varslene dine, og får tilgang til tillatelsene for telefon, SMS, kontakter, kalender, samtalelogger og enheter i nærheten."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Denne appen får tillatelse til å synkronisere informasjon som navnet til noen som ringer, og har disse tillatelsene på din/ditt <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Velg en enhet som skal administreres av <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal konfigureres"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Denne appen får tillatelse til å synkronisere informasjon som navnet til noen som ringer, og har disse tillatelsene på <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrere <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"briller"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilgang til varslene dine og får tillatelsene for telefon, SMS, kontakter, mikrofon og enheter i nærheten."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Denne appen får disse tillatelsene på din/ditt <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Denne appen får disse tillatelsene på <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper mellom enhetene dine, på vegne av <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du la <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> gjøre dette?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til å strømme apper og andre systemfunksjoner til enheter i nærheten"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og den valgte enheten"</string>
<string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
<string name="consent_back" msgid="2560683030046918882">"Tilbake"</string>
<string name="permission_expand" msgid="893185038020887411">"Vis <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 1f4506a..a5ca130 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> प्रयोग गर्ने अनुमति दिने हो?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
- <string name="chooser_title" msgid="2262294130493605839">"आफूले <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
- <string name="summary_watch" msgid="898569637110705523">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एप चाहिन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने, तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, पात्रो, कल लग तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने र यी कुराहरू गर्ने अनुमति दिइने छ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"आफूले <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको डिभाइस चयन गर्नुहोस्"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"सेट अप गर्नका लागि <xliff:g id="PROFILE_NAME">%1$s</xliff:g> छनौट गर्नुहोस्"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा यो एपलाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने र यी कुराहरू गर्ने अनुमति दिइने छ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापन गर्ने अनुमति दिने हो?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"चस्मा"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एप चाहिन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, माइक्रोफोन तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई निम्न अनुमति दिइने छ:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"डिभाइस"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा यो एपलाई निम्न अनुमति दिइने छ:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> लाई यो कार्य गर्ने अनुमति दिने हो?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट नजिकैका डिभाइसहरूमा एप र सिस्टमका अन्य सुविधाहरू स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने <xliff:g id="DEVICE_NAME">%1$s</xliff:g> का बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string>
<string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"रद्द गर्नुहोस्"</string>
<string name="consent_back" msgid="2560683030046918882">"पछाडि"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> एक्स्पान्ड गर्नुहोस्"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोल्याप्स गर्नुहोस्"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 7c79cb4..8c29b9f 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Deze app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> mag informatie (zoals de naam van iemand die belt) synchroniseren, mag interactie hebben met je meldingen en krijgt toegang tot de rechten Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Deze app kan informatie synchroniseren (zoals de naam van iemand die belt) en krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Een apparaat kiezen om te beheren met <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om in te stellen"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Deze app kan informatie synchroniseren (zoals de naam van iemand die belt) en krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te beheren?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"brillen"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Deze app is nodig om <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> mag interactie hebben met je meldingen en krijgt toegang tot de rechten voor Telefoon, Sms, Contacten, Microfoon en Apparaten in de buurt."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Deze app krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"apparaat"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Deze app krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toestemming om apps te streamen tussen je apparaten"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Toestaan dat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> deze actie uitvoert?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens je <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en andere systeemfuncties naar apparaten in de buurt te streamen"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string>
<string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
<string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Annuleren"</string>
<string name="consent_back" msgid="2560683030046918882">"Terug"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> uitvouwen"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> samenvouwen"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index dbff4e2..f7d814c 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
- <string name="summary_watch" msgid="898569637110705523">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବା, ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କର ଫୋନ, SMS, କଣ୍ଟାକ୍ଟ, କେଲେଣ୍ଡର, କଲ ଲଗ ଓ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏବଂ ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ ଡିଭାଇସ ବାଛନ୍ତୁ"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ସେଟ ଅପ କରିବାକୁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ବାଛନ୍ତୁ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏବଂ ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ଚଷମା"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କର ଫୋନ, SMS, କଣ୍ଟାକ୍ଟ, ମାଇକ୍ରୋଫୋନ ଓ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ଡିଭାଇସ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ଏହି ପଦକ୍ଷେପ ନେବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକରେ ଆପ୍ସ ଏବଂ ଅନ୍ୟ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ଆପଣଙ୍କ ଫୋନ ଏବଂ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string>
<string name="summary_generic" msgid="1761976003668044801">"ଆପଣଙ୍କ ଫୋନ ଏବଂ ବଛାଯାଇଥିବା ଡିଭାଇସ ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string>
<string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index 91b5264..3169ded 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
<string name="confirmation_title" msgid="4593465730772390351">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
- <string name="summary_watch" msgid="898569637110705523">"ਇਹ ਐਪ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰਨ, ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਕੈਲੰਡਰ, ਕਾਲ ਲੌਗਾਂ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> \'ਤੇ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰਨ ਅਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ ਕੋਈ ਡੀਵਾਈਸ ਚੁਣੋ"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> \'ਤੇ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰਨ ਅਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ਐਨਕਾਂ"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ਇਹ ਐਪ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> \'ਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"ਡੀਵਾਈਸ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> \'ਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ਕੀ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ਨੂੰ ਇਹ ਕਾਰਵਾਈ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ \'ਤੇ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string>
<string name="summary_generic" msgid="1761976003668044801">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਚੁਣੇ ਗਏ ਡੀਵਾਈਸ ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string>
<string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string>
<string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ਰੱਦ ਕਰੋ"</string>
<string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਨੂੰ ਸਮੇਟੋ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 1432a45..8daa15b 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Zezwolić na dostęp aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do tego urządzenia (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Wybierz <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ta aplikacja jest niezbędna do zarządzania urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła synchronizować informacje takie jak nazwa osoby dzwoniącej, korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i Urządzeń w pobliżu."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aplikacja będzie mogła synchronizować informacje takie jak nazwa dzwoniącego oraz korzystać z tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Wybierz urządzenie, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, aby go skonfigurować"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aplikacja będzie mogła synchronizować informacje takie jak nazwa dzwoniącego oraz korzystać z tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zezwolić na dostęp aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do urządzenia <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Okulary"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta aplikacja jest niezbędna do zarządzania urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła wchodzić w interakcję z powiadomieniami i korzystać z uprawnień dotyczących telefonu, SMS-ów, kontaktów, mikrofonu oraz urządzeń w pobliżu."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aplikacja będzie miała dostęp do tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"urządzenie"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aplikacja będzie miała dostęp do tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Zezwól urządzeniu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Zezwolić urządzeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> na wykonanie tego działania?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o uprawnienia do strumieniowego odtwarzania treści i innych funkcji systemowych na urządzeniach w pobliżu"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta aplikacja może synchronizować informacje takie jak nazwa osoby dzwoniącej między Twoim telefonem i urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ta aplikacja może synchronizować informacje takie jak nazwa osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string>
<string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
<string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Anuluj"</string>
<string name="consent_back" msgid="2560683030046918882">"Wstecz"</string>
<string name="permission_expand" msgid="893185038020887411">"Rozwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Zwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index c45cda6..c0224da 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá sincronizar informações, como o nome de quem está ligando, interagir com suas notificações e acessar as permissões do Telefone, SMS, contatos, agenda, registro de chamadas e dispositivos por perto."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá interagir com suas notificações e acessar suas permissões de telefone, SMS, contatos, microfone e dispositivos por perto."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 8619ff4..cc5f81b 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Esta app é necessária para gerir o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder sincronizar informações, como o nome do autor de uma chamada, interagir com as suas notificações e aceder às autorizações do Telemóvel, SMS, Contactos, Calendário, Registos de chamadas e Dispositivos próximos."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, e aceder a estas autorizações no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerido pela app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Escolha um perfil de <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, e aceder a estas autorizações no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça a gestão do dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta app é necessária para gerir o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com as suas notificações e aceder às autorizações do Telemóvel, SMS, Contactos, Microfone e Dispositivos próximos."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Esta app vai poder aceder a estas autorizações no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Esta app vai poder aceder a estas autorizações no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça esta ação?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e outras funcionalidades do sistema para dispositivos próximos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_expand" msgid="893185038020887411">"Expandir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Reduzir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index c45cda6..c0224da 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá sincronizar informações, como o nome de quem está ligando, interagir com suas notificações e acessar as permissões do Telefone, SMS, contatos, agenda, registro de chamadas e dispositivos por perto."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá interagir com suas notificações e acessar suas permissões de telefone, SMS, contatos, microfone e dispositivos por perto."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index f74e08ee..203cda4 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Alege un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să sincronizeze informații, cum ar fi numele unui apelant, să interacționeze cu notificările tale și să îți acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, și să acceseze aceste permisiuni pe <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Alege un dispozitiv pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Alege un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> de configurat"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, și să acceseze aceste permisiuni pe <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să gestioneze <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"ochelari"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările tale și să-ți acceseze permisiunile pentru Telefon, SMS, Agendă, Microfon și Dispozitive din apropiere."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Aplicația va putea să acceseze următoarele permisiuni pe <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"dispozitiv"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Aplicația va putea să acceseze următoarele permisiuni pe <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permite ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele tale"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permiți ca <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> să realizeze această acțiune?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream conținut din aplicații și alte funcții de sistem pe dispozitivele din apropiere"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și dispozitivul ales"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permite"</string>
<string name="consent_no" msgid="2640796915611404382">"Nu permite"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Anulează"</string>
<string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
<string name="permission_expand" msgid="893185038020887411">"Extinde <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Restrânge <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index cdf1668..1644f0d2 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Предоставить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ к устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" сможет синхронизировать данные, например из журнала звонков, а также получит доступ к уведомлениям и разрешениям \"Телефон\", \"Контакты\", \"Календарь\", \"Список вызовов\", \"Устройства поблизости\" и SMS."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Это приложение сможет синхронизировать данные, например имена вызывающих абонентов, а также получит указанные разрешения на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберите устройство, которым будет управлять приложение <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Выберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для настройки"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Это приложение сможет синхронизировать данные, например имена вызывающих абонентов, а также получит указанные разрешения на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять устройством <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Очки"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" сможет взаимодействовать с уведомлениями, а также получит разрешения \"Телефон\", SMS, \"Контакты\", \"Микрофон\" и \"Устройства поблизости\"."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Это приложение получит указанные разрешения на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"устройстве"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Это приложение получит указанные разрешения на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, чтобы транслировать приложения между устройствами."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Разрешить приложению <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> выполнять это действие?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения и системные функции на устройства поблизости."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Приложение сможет синхронизировать информацию между телефоном и устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", например данные из журнала звонков."</string>
<string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string>
<string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
<string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Отмена"</string>
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Разворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
<string name="permission_collapse" msgid="3320833884220844084">"Сворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 41224c6..57a6bce 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> වෙත ප්රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
- <string name="summary_watch" msgid="898569637110705523">"මෙම යෙදුමට ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> හට අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට, ඔබේ දැනුම්දීම් සමග අන්තර්ක්රියා කිරීමට සහ ඔබේ දුරකථනය, SMS, සම්බන්ධතා, දින දර්ශනය, ඇමතුම් ලොග සහ අවට උපාංග අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"මෙම යෙදුමට අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට, සහ ඔබේ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> මත මෙම අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> විසින් කළමනා කරනු ලැබීමට උපාංගයක් තෝරන්න"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"සැකසීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"මෙම යෙදුමට අමතන කෙනෙකුගේ නම වැනි, තොරතුරු සමමුහූර්ත කිරීමට, සහ ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> මත මෙම අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ලැබේ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> කළමනා කිරීමට ඉඩ දෙන්න ද?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"කණ්ණාඩි"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනා කිරීමට මෙම යෙදුම අවශ්යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> හට ඔබේ දැනුම්දීම් සමග අන්තර්ක්රියා කිරීමට සහ ඔබේ දුරකථනය, කෙටි පණිවුඩය, සම්බන්ධතා, මයික්රොෆෝනය සහ අවට උපාංග අවසර වෙත ප්රවේශ වීමට ඉඩ දෙයි."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"මෙම යෙදුමට ඔබේ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> මත මෙම අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"උපාංගය"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"මෙම යෙදුමට ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> මත මෙම අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ලැබේ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්රවේශ වීමට ඉඩ දෙන්න"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ උපාංග අතර යෙදුම් ප්රවාහ කිරීමට අවසරය ඉල්ලමින් සිටියි"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"මෙම ක්රියාව කිරීමට <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> හට ඉඩ දෙන්න ද?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් යෙදුම් සහ අනෙකුත් පද්ධති විශේෂාංග අවට උපාංග වෙත ප්රවාහ කිරීමට අවසර ඉල්ලයි"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"මෙම යෙදුමට ඔබේ දුරකථනය සහ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string>
<string name="summary_generic" msgid="1761976003668044801">"මෙම යෙදුමට ඔබේ දුරකථනය සහ තෝරා ගත් උපාංගය අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string>
<string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
<string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"අවලංගු කරන්න"</string>
<string name="consent_back" msgid="2560683030046918882">"ආපසු"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> විදහන්න"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> හකුළන්න"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 7514ee3..e6e0ce8 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť synchronizovať informácie, napríklad meno volajúceho, interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov, kalendára, zoznamu hovorov a zariadení v okolí."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, a získavať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zariadenie, ktoré bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý nastavíte"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, a získavať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovať zariadenie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"okuliare"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k povoleniam pre telefón, SMS, kontakty, mikrofón a zariadenia v okolí."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Táto aplikácia bude mať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"zariadenie"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Táto aplikácia bude mať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie streamovať aplikácie medzi vašimi zariadeniami."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Chcete povoliť zariadeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> vykonať túto akciu?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie a ďalšie systémové funkcie do zariadení v okolí"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string>
<string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Zrušiť"</string>
<string name="consent_back" msgid="2560683030046918882">"Späť"</string>
<string name="permission_expand" msgid="893185038020887411">"Rozbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Zbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 562e474..85d657d 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Izbira profila »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>«, ki ga bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bodo omogočene sinhronizacija podatkov, na primer imena klicatelja, interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Koledar, Dnevniki klicev in Naprave v bližini."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, in dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Izbira naprave, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Izberite profil naprave »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>« za nastavitev"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, in dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti upravljanje naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"očala"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bosta omogočeni interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Mikrofon in Naprave v bližini."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Ta aplikacija bo lahko dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"naprava"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Ta aplikacija bo lahko dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij v vaših napravah."</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ali napravi <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dovolite izvedbo tega dejanja?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij in drugih sistemskih funkcij v napravah v bližini."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in napravi »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«."</string>
<string name="summary_generic" msgid="1761976003668044801">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in izbrani napravi."</string>
<string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Prekliči"</string>
<string name="consent_back" msgid="2560683030046918882">"Nazaj"</string>
<string name="permission_expand" msgid="893185038020887411">"Razširi dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Strni dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 8e32ec7..f7144db 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
<string name="confirmation_title" msgid="4593465730772390351">"T\'i lejohet <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> qasja te <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Zgjidh që <xliff:g id="PROFILE_NAME">%1$s</xliff:g> të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ky aplikacion nevojitet për të menaxhuar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të sinkronizojë informacione, si p.sh. emrin e dikujt që po telefonon, të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Kalendarit\", \"Evidencave të telefonatave\" dhe \"Pajisjeve në afërsi\"."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Këtij aplikacioni do t\'i lejohet të sinkronizojë informacione, si p.sh. emrin e dikujt që po telefonon, si dhe të ketë qasje në këto leje në <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Zgjidh një pajisje që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Zgjidh një <xliff:g id="PROFILE_NAME">%1$s</xliff:g> për konfigurimin"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Këtij aplikacioni do t\'i lejohet të sinkronizojë informacione, si p.sh. emrin e dikujt që po telefonon, si dhe të ketë qasje në këto leje në <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të menaxhojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"syzet"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ky aplikacion nevojitet për të menaxhuar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Mikrofonit\" dhe të \"Pajisjeve në afërsi\"."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Këtij aplikacioni do t\'i lejohet qasja te këto leje në <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"pajisje"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Këtij aplikacioni do t\'i lejohet qasja te këto leje në <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të ndërmarrë këtë veprim?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) tënde për të transmetuar aplikacione dhe veçori të tjera të sistemit te pajisjet në afërsi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin i dikujt që po telefonon, mes telefonit tënd dhe <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string>
<string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
<string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Anulo"</string>
<string name="consent_back" msgid="2560683030046918882">"Pas"</string>
<string name="permission_expand" msgid="893185038020887411">"Zgjero: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Palos: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 34d9ca2..0b634c5 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Одаберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за синхронизовање информација, попут особе која упућује позив, за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, календар, евиденције позива и уређаје у близини."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Овој апликацији ће бити дозвољено да синхронизује податке, попут имена особе која упућује позив, и приступа тим дозволама на вашем уређају (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Одаберите уређај којим ће управљати апликација <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> који желите да подесите"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Овој апликацији ће бити дозвољено да синхронизује податке, попут имена особе која упућује позив, и приступа тим дозволама на вашем уређају (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Желите ли да дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управља уређајем <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"наочаре"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, микрофон и уређаје у близини."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Овој апликацији ће бити дозвољено да приступа овим дозволама на вашем уређају (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"уређај"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Овој апликацији ће бити дозвољено да приступа овим дозволама на вашем уређају (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за стримовање апликација између уређаја"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Желите ли да дозволите да <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> обави ову радњу?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације и друге системске функције на уређаје у близини"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и уређаја <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и одабраног уређаја"</string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Скупи <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 54e2d18..b442412 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Vill du tillåta att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får åtkomst till <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att synkronisera information, till exempel namnet på någon som ringer, interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Kalender, Samtalsloggar och Enheter i närheten."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Appen får tillåtelse att synkronisera information, till exempel namnet på någon som ringer, och få tillgång till dessa behörigheter på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Välj en enhet för hantering av <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för konfigurering"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Appen får tillåtelse att synkronisera information, till exempel namnet på någon som ringer, och få tillgång till dessa behörigheter på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Tillåt att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hanterar <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasögon"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Mikrofon och Enheter i närheten."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Appen får tillåtelse att använda dessa behörigheter på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"enhet"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Appen får tillåtelse att använda dessa behörigheter på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att låta <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> streama appar mellan enheter"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vill du tillåta att <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> utför denna åtgärd?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att streama appar och andra systemfunktioner till enheter i närheten för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Den här appen kommer att kunna synkronisera information mellan telefonen och <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, till exempel namnet på någon som ringer"</string>
<string name="summary_generic" msgid="1761976003668044801">"Den här appen kommer att kunna synkronisera information mellan telefonen och den valda enheten, till exempel namnet på någon som ringer"</string>
<string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
<string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string>
<string name="permission_expand" msgid="893185038020887411">"Utöka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Komprimera <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 6e8c607..92932c7 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kutumia arifa zako na ruhusa zako za Simu, SMS, Anwani, Maikrofoni na vifaa vilivyo Karibu."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Programu hii itaruhusiwa kusawazisha maelezo, kama vile jina la mtu anayepiga simu na kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yako"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Chagua kifaa cha kudhibitiwa na <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili uweke mipangilio"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Programu hii itaruhusiwa kusawazisha maelezo, kama vile jina la mtu anayepiga simu na kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> idhibiti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"miwani"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kutumia arifa zako na kufikia ruhusa zako za Simu, SMS, Anwani, Maikrofoni na Vifaa vilivyo Karibu."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Programu hii itaruhusiwa kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yako"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"kifaa"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Programu hii itaruhusiwa kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yako ili itiririshe programu kati ya vifaa vyako"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ungependa kuruhusu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> itekeleze kitendo hiki?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> chako ili itiririshe programu na vipengele vingine vya mfumo kwenye vifaa vilivyo karibu"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu na <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako"</string>
<string name="summary_generic" msgid="1761976003668044801">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu yako na kifaa ulichochagua"</string>
<string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
<string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Ghairi"</string>
<string name="consent_back" msgid="2560683030046918882">"Nyuma"</string>
<string name="permission_expand" msgid="893185038020887411">"Panua <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Kunja <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index d049953..c3fef61 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்தை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட வேண்டும்"</string>
- <string name="summary_watch" msgid="898569637110705523">"உங்கள் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவை. அழைப்பவரின் பெயர் போன்ற தகவலை ஒத்திசைத்தல், உங்கள் அறிவிப்புகளைப் பார்த்தல், உங்கள் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர், அழைப்புப் பதிவுகள், அருகிலுள்ள சாதனங்களை அணுகுதல் ஆகியவற்றுக்கு <xliff:g id="APP_NAME">%2$s</xliff:g> அனுமதிக்கப்படும்."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"அழைப்பவரின் பெயர் போன்ற தகவல்களை ஒத்திசைக்கவும் உங்கள் <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுகவும் இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸால் நிர்வகிக்கப்பட வேண்டிய சாதனத்தைத் தேர்வுசெய்யுங்கள்"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"அமைக்க <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்வுசெய்யவும்"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"அழைப்பவரின் பெயர் போன்ற தகவல்களை ஒத்திசைக்கவும் உங்கள் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுகவும் இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong&gt சாதனத்தை நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"கிளாஸஸ்"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவை. உங்கள் மொபைல், மெசேஜ், தொடர்புகள், மைக்ரோஃபோன், அருகிலுள்ள சாதனங்கள் ஆகியவற்றுக்கான அணுகலையும் உங்கள் அறிவிப்புகளைப் பார்ப்பதற்கான அனுமதியையும் <xliff:g id="APP_NAME">%2$s</xliff:g> பெறும்."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"உங்கள் <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுக இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"சாதனம்"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"உங்கள் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுக இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவும்"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"பன்முக சாதன சேவைகள்"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் அனுமதியைக் கோருகிறது"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"இந்தச் செயலைச் செய்ய <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ஐ அனுமதிக்கவா?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"அருகிலுள்ள சாதனங்களுக்கு ஆப்ஸையும் பிற சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கோருகிறது"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"அழைப்பவரின் பெயர் போன்ற தகவலை உங்கள் மொபைல் மற்றும் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்திற்கு இடையில் இந்த ஆப்ஸால் ஒத்திசைக்க முடியும்"</string>
<string name="summary_generic" msgid="1761976003668044801">"அழைப்பவரின் பெயர் போன்ற தகவலை உங்கள் மொபைல் மற்றும் தேர்வுசெய்த சாதனத்திற்கு இடையில் இந்த ஆப்ஸால் ஒத்திசைக்க முடியும்"</string>
<string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
<string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ரத்துசெய்"</string>
<string name="consent_back" msgid="2560683030046918882">"பின்செல்"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐ விரிவாக்கும்"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐச் சுருக்கும்"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 5e91614..95a5ace 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
- <string name="summary_watch" msgid="898569637110705523">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి, అలాగే మీ ఫోన్, SMS, కాంటాక్ట్లు, క్యాలెండర్, కాల్ లాగ్లు, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడే పరికరాన్ని ఎంచుకోండి"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"సెటప్ చేయడానికి <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"గ్లాసెస్"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి, అలాగే మీ ఫోన్, SMS, కాంటాక్ట్లు, మైక్రోఫోన్, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"మీ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"పరికరం"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"మీ పరికరాల మధ్య యాప్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ఈ చర్యను అమలు చేయడానికి <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"సమీపంలోని పరికరాలకు యాప్లను, ఇతర సిస్టమ్ ఫీచర్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్కి, <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి మధ్య సింక్ చేయగలుగుతుంది"</string>
<string name="summary_generic" msgid="1761976003668044801">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్ కు, ఎంచుకున్న పరికరానికీ మధ్య సింక్ చేయగలుగుతుంది"</string>
<string name="consent_yes" msgid="8344487259618762872">"అనుమతించండి"</string>
<string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"రద్దు చేయండి"</string>
<string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ను విస్తరించండి"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ను కుదించండి"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 46e631c..dc9e242 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึง <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
- <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้ซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา โต้ตอบกับการแจ้งเตือน รวมถึงมีสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ปฏิทิน, บันทึกการโทร และอุปกรณ์ที่อยู่ใกล้เคียง"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"แอปนี้จะได้รับอนุญาตให้ซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา และมีสิทธิ์เข้าถึงข้อมูลเหล่านี้ใน<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ของคุณ"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"เลือกอุปกรณ์ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะตั้งค่า"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"แอปนี้จะได้รับอนุญาตให้ซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา และมีสิทธิ์เข้าถึงข้อมูลเหล่านี้ใน<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ของคุณ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> จัดการ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ไหม"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"แว่นตา"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและมีสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ไมโครโฟน และอุปกรณ์ที่อยู่ใกล้เคียง"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"แอปนี้จะได้รับสิทธิ์ดังต่อไปนี้ใน<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ของคุณ"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"อุปกรณ์"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"แอปนี้จะได้รับสิทธิ์ดังต่อไปนี้ใน<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ของคุณ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"อนุญาตให้ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ทำงานนี้ไหม"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปและฟีเจอร์อื่นๆ ของระบบไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและ<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ได้"</string>
<string name="summary_generic" msgid="1761976003668044801">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและอุปกรณ์ที่เลือกไว้ได้"</string>
<string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
<string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"ยกเลิก"</string>
<string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
<string name="permission_expand" msgid="893185038020887411">"ขยาย <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"ยุบ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index b358870..f50da1b 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Kailangan ang app na ito para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, makipag-ugnayan sa mga notification mo, at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, Kalendaryo, Mga log ng tawag, at Mga kalapit na device."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Papayagan ang app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, at i-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Pumili ng device na papamahalaan ng <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para mag-set up"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Papayagan ang app na ito na mag-sync ng impormasyon, tulad ng pangalan ng taong tumatawag, at i-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na pamahalaan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"salamin"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Kailangan ang app na ito para mapamahalaan ang <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga notification mo at i-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, Mikropono, at Mga kalapit na device."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Papayagan ang app na ito na i-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Papayagan ang app na ito na i-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyong ito sa iyong telepono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mag-stream ng mga app sa pagitan ng mga device mo"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Payagan ang <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> na gawin ang pagkilos na ito?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Humihiling ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mag-stream ng mga app at iba pang feature ng system sa mga kalapit na device"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng napiling device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
<string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Kanselahin"</string>
<string name="consent_back" msgid="2560683030046918882">"Bumalik"</string>
<string name="permission_expand" msgid="893185038020887411">"I-expand ang <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"I-collapse ang <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index c5229ab..fbe9b02 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına erişmesi için <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına izin verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" msgid="898569637110705523">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine, bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Takvim, Arama kayıtları ve Yakındaki cihazlar izinlerine erişmesine izin verilir."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Bu uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine ve <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazınızda aşağıdaki izinlere erişmesine izin verilir"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tarafından yönetilecek bir cihaz seçin"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Ayarlamak için bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Bu uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine ve <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda aşağıdaki izinlere erişmesine izin verilir"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazını yönetmesi için izin verilsin mi?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazının yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Mikrofon ve Yakındaki cihazlar izinlerine erişmesine izin verilir."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Bu uygulamanın <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazınızda şu izinlere erişmesine izin verilecek:"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"cihaz"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Bu uygulamanın <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda şu izinlere erişmesine izin verilecek:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akışı gerçekleştirmek için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazının bu işlemi yapmasına izin verilsin mi?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına uygulamaları ve diğer sistem özelliklerini yakındaki cihazlara aktarmak için izin istiyor"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaz arasında senkronize edebilir"</string>
<string name="summary_generic" msgid="1761976003668044801">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve seçili cihaz arasında senkronize edebilir"</string>
<string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
<string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"İptal"</string>
<string name="consent_back" msgid="2560683030046918882">"Geri"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini genişlet"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini daralt"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 221a869..aa7438b 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Надати додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до інформації на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає), взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Календар\", \"Журнали викликів\" і \"Пристрої поблизу\"."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) і отримає доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Виберіть пристрій, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для налаштування"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) і отримає доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> керувати пристроєм <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"окуляри"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Мікрофон\" і \"Пристрої поблизу\"."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Цей додаток матиме доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"пристрій"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Цей додаток матиме доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" запитує дозвіл на трансляцію додатків між вашими пристроями"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Дозволити додатку <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> виконувати цю дію?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) запитує дозвіл на трансляцію додатків та інших системних функцій на пристрої поблизу"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string>
<string name="summary_generic" msgid="1761976003668044801">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і вибраним пристроєм"</string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Скасувати"</string>
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_expand" msgid="893185038020887411">"Розгорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
<string name="permission_collapse" msgid="3320833884220844084">"Згорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 8acfc29..9cf41cf 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> تک رسائی کی اجازت دیں؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
- <string name="summary_watch" msgid="898569637110705523">"آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لیے اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے، آپ کی اطلاعات کے ساتھ تعامل کرنے، آپ کے فون، SMS، رابطے، کیلنڈر، کال لاگز اور قریبی آلات کی اجازتوں تک رسائی حاصل کرنے کی اجازت ہوگی۔"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے اور ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کے ذریعے منتخب کیے جانے کیلئے آلہ منتخب کریں"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"اس ایپ کو آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> پر کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے اور ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کا نظم کرنے کی اجازت دیں؟"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"گلاسز"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لیے، اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں، مائیکروفون اور قریبی آلات کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"آلہ"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"اس ایپ کو آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> پر ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ڈیوائس سروسز"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> کو یہ کارروائی انجام دینے کی اجازت دیں؟"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> آپ کے <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے ایپس اور سسٹم کی دیگر خصوصیات کی سلسلہ بندی قریبی آلات پر کرنے کی اجازت طلب کر رہی ہے"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"یہ ایپ آپ کے فون اور <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string>
<string name="summary_generic" msgid="1761976003668044801">"یہ ایپ آپ کے فون اور منتخب کردہ آلے کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string>
<string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string>
<string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"منسوخ کریں"</string>
<string name="consent_back" msgid="2560683030046918882">"پیچھے"</string>
<string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> کو پھیلائیں"</string>
<string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> کو سکیڑیں"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 95d5b1b..42dcd72 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
- <string name="summary_watch" msgid="898569637110705523">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga chaqiruvchining ismi, bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, taqvim, chaqiruvlar jurnali va yaqin-atrofdagi qurilmalarni aniqlash kabi maʼlumotlarni sinxronlashga ruxsat beriladi."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Bu ilovaga chaqiruvchining ismi kabi maʼlumotlarni sinxronlash va <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> qurilmasida quyidagi amallarni bajarishga ruxsat beriladi"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> boshqaradigan qurilmani tanlang"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Sozlash uchun <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilini tanlang"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Bu ilovaga chaqiruvchining ismi kabi maʼlumotlarni sinxronlash va <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasida quyidagi amallarni bajarishga ruxsat beriladi"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasini boshqarish uchun ruxsat berilsinmi?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"koʻzoynak"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, mikrofon va yaqin-atrofdagi qurilmalarga kirishga ruxsat beriladi."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Bu ilova <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> qurilmasida quyidagi ruxsatlarni oladi"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"qurilma"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasida quyidagi ruxsatlarni oladi"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Qurilamalararo ilovalar strimingi uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ilovasiga bu amalni bajarish uchun ruxsat berilsinmi?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME">%2$s</xliff:g> qurilmangizdan nomidan atrofdagi qurilmalarga ilova va boshqa tizim funksiyalarini uzatish uchun ruxsat olmoqchi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Bu ilova telefoningiz va <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasida chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string>
<string name="summary_generic" msgid="1761976003668044801">"Bu ilova telefoningiz va tanlangan qurilmada chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string>
<string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Bekor qilish"</string>
<string name="consent_back" msgid="2560683030046918882">"Orqaga"</string>
<string name="permission_expand" msgid="893185038020887411">"Yoyish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Yopish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 24fdd4a..51f69b2 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Trình quản lý thiết bị đồng hành"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> quản lý"</string>
- <string name="summary_watch" msgid="898569637110705523">"Cần ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> được phép đồng bộ hoá thông tin (ví dụ: tên người gọi), tương tác với thông báo cũng như có các quyền truy cập Điện thoại, Tin nhắn SMS, Danh bạ, Lịch, Nhật ký cuộc gọi và Thiết bị ở gần."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Ứng dụng này sẽ được phép đồng bộ hoá thông tin (chẳng hạn như tên của người đang gọi điện) và dùng những quyền sau trên <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> của bạn"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Chọn một thiết bị sẽ do <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> để thiết lập"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Ứng dụng này sẽ được phép đồng bộ hoá thông tin (chẳng hạn như tên của người đang gọi điện) và dùng những quyền sau trên <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"kính"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bạn cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> sẽ được phép tương tác với thông báo của bạn, cũng như sử dụng các quyền đối với Điện thoại, SMS, Danh bạ, Micrô và Thiết bị ở gần."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Ứng dụng này sẽ được phép dùng những quyền sau trên <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> của bạn"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"thiết bị"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Ứng dụng này sẽ được phép dùng những quyền sau trên <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> để truyền trực tuyến ứng dụng giữa các thiết bị của bạn"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Cho phép <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> thực hiện hành động này?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang thay <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yêu cầu quyền truyền trực tuyến ứng dụng và các tính năng khác của hệ thống đến các thiết bị ở gần"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và thiết bị bạn chọn"</string>
<string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
<string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Huỷ"</string>
<string name="consent_back" msgid="2560683030046918882">"Quay lại"</string>
<string name="permission_expand" msgid="893185038020887411">"Mở rộng <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Thu gọn <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 401a263..578302b 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
<string name="confirmation_title" msgid="4593465730772390351">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>访问<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
- <string name="chooser_title" msgid="2262294130493605839">"选择要由<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="898569637110705523">"需要使用此应用才能管理您的设备“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”。<xliff:g id="APP_NAME">%2$s</xliff:g>将能同步信息(例如来电者的姓名)、与通知交互,并能获得对电话、短信、通讯录、日历、通话记录和附近设备的访问权限。"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"该应用将可以同步信息(例如来电者的姓名),并可以获得您<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的以下权限"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"选择要由<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理的设备"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"选择 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 进行设置"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"该应用将可以同步信息(例如来电者的姓名),并可以获得您<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上的以下权限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"眼镜"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"需要使用此应用才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。“<xliff:g id="APP_NAME">%2$s</xliff:g>”将能与通知交互,并可获得电话、短信、通讯录、麦克风和附近设备的访问权限。"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"该应用将可以获得您<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的以下权限"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"设备"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"该应用将可以获得您<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上的以下权限"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>访问您手机中的这项信息"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请求在您的设备之间流式传输应用内容"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"允许<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>进行此操作?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_NAME">%2$s</xliff:g>请求将应用和其他系统功能流式传输到附近的设备"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"此应用将能在您的手机和“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”之间同步信息,例如来电者的姓名"</string>
<string name="summary_generic" msgid="1761976003668044801">"此应用将能在您的手机和所选设备之间同步信息,例如来电者的姓名"</string>
<string name="consent_yes" msgid="8344487259618762872">"允许"</string>
<string name="consent_no" msgid="2640796915611404382">"不允许"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_expand" msgid="893185038020887411">"展开<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"收起<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 52230cb..22694eb 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
<string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
- <string name="chooser_title" msgid="2262294130493605839">"選擇由 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="898569637110705523">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可同步資訊 (例如來電者的名稱)、透過通知與你互動,並存取電話、短訊、通訊錄、日曆、通話記錄和附近的裝置權限。"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"此應用程式將可同步資訊 (例如來電者的名稱),並可在<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上取得以下權限"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 管理的裝置"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"此應用程式將可同步資訊 (例如來電者的名稱),並可在<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上取得以下權限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可透過通知與你互動,並存取電話、短訊、通訊錄、麥克風和附近的裝置權限。"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"此應用程式將可在<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上取得以下權限"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"此應用程式將可在<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上取得以下權限"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取你手機中的這項資料"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 要求權限,以便在裝置間串流應用程式的內容"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"要允許「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」<strong></strong>執行此操作嗎?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求權限,才能在附近的裝置上串流播放應用程式和其他系統功能"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"此應用程式將可同步手機和「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」的資訊,例如來電者的名稱"</string>
<string name="summary_generic" msgid="1761976003668044801">"此應用程式將可同步手機和所選裝置的資訊,例如來電者的名稱"</string>
<string name="consent_yes" msgid="8344487259618762872">"允許"</string>
<string name="consent_no" msgid="2640796915611404382">"不允許"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index c680157..a8151de 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
<string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
- <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="898569637110705523">"你必須使用這個應用程式,才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可同步資訊 (例如來電者名稱)、存取通知及在通知上執行操作,並取得電話、簡訊、聯絡人、日曆、通話記錄、麥克風和鄰近裝置權限。"</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"這個應用程式將可同步處理資訊 (例如來電者名稱)、取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理的裝置"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"這個應用程式將可同步處理資訊 (例如來電者名稱)、取得<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上的這些權限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知及在通知上執行操作,並取得電話、簡訊、聯絡人、麥克風和鄰近裝置權限。"</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"這個應用程式將可取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"這個應用程式將可取得<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上的這些權限"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取手機中的這項資訊"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"為了在裝置間串流傳輸應用程式內容,「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 要求相關權限"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"要允許「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」<strong></strong>執行這項操作嗎?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求必要權限,才能在鄰近裝置上串流播放應用程式和其他系統功能"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"這個應用程式將可在手機和「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」之間同步資訊,例如來電者名稱"</string>
<string name="summary_generic" msgid="1761976003668044801">"這個應用程式將可在手機和指定裝置間同步資訊,例如來電者名稱"</string>
<string name="consent_yes" msgid="8344487259618762872">"允許"</string>
<string name="consent_no" msgid="2640796915611404382">"不允許"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 22495e2..d9b5c52 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -19,13 +19,12 @@
<string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
<string name="confirmation_title" msgid="4593465730772390351">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
- <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" msgid="898569637110705523">"Le app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, ukusebenzisana nezaziso zakho futhi ufinyelele Ifoni yakho, i-SMS, Oxhumana Nabo, Ikhalenda, Amarekhodi Amakholi nezimvume zamadivayisi aseduze."</string>
- <string name="summary_watch_single_device" msgid="3173948915947011333">"Le-app izovunyelwa ukuvumelanisa ulwazi, olufana negama lomuntu ofonayo, iphinde ifinyelele lezi zimvume ku-<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yakho"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Khetha idivayisi engaphathwa nge-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ukusetha"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Le-app izovunyelwa ukuvumelanisa ulwazi, olufana negama lomuntu ofonayo, iphinde ifinyelele lezi zimvume ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuthi ifinyelele i-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
- <string name="profile_name_glasses" msgid="8488394059007275998">"Izingilazi"</string>
- <string name="summary_glasses_multi_device" msgid="615259525961937348">"Le app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele kufoni yakho, i-SMS, Oxhumana nabo, Imakrofoni Nezimvume zamadivayisi aseduze."</string>
- <string name="summary_glasses_single_device" msgid="3000909894067413398">"Le-app izovunyelwa ukufinyelela lezi zimvume ku-<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yakho"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"idivayisi"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Le-app izovunyelwa ukufinyelela lezi zimvume ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifinyelele lolu lwazi kusukela efonini yakho"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string>
@@ -38,10 +37,10 @@
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vumela i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ukwenza lesi senzo?"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukusakaza ama-app nezinye izakhi zesistimu kumadivayisi aseduze"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
- <string name="summary_generic_single_device" msgid="4181180669689590417">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho ne-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="summary_generic" msgid="1761976003668044801">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho nedivayisi ekhethiwe"</string>
<string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
<string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
+ <string name="consent_cancel" msgid="5655005528379285841">"Khansela"</string>
<string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
<string name="permission_expand" msgid="893185038020887411">"Nweba i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Goqa i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 2502bbf..5398579 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -28,13 +28,13 @@
<string name="profile_name_watch">watch</string>
<!-- Title of the device selection dialog. -->
- <string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to be managed by <strong><xliff:g id="app_name" example="Android Wear">%2$s</xliff:g></strong></string>
+ <string name="chooser_title_non_profile">Choose a device to be managed by <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong></string>
- <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile (type) [CHAR LIMIT=NONE] -->
- <string name="summary_watch">This app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.</string>
+ <!-- Tile of the multiple devices' dialog. -->
+ <string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to set up</string>
- <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] -->
- <string name="summary_watch_single_device">This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></string>
+ <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile [CHAR LIMIT=NONE] -->
+ <string name="summary_watch">This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="device_name" example="phone">%1$s</xliff:g></string>
<!-- ================= DEVICE_PROFILE_GLASSES ================= -->
@@ -42,13 +42,10 @@
<string name="confirmation_title_glasses">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to manage <strong><xliff:g id="device_name" example="Glasses">%2$s</xliff:g></strong>?</string>
<!-- The name of the "glasses" device type [CHAR LIMIT=30] -->
- <string name="profile_name_glasses">glasses</string>
+ <string name="profile_name_glasses">device</string>
- <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile (type) [CHAR LIMIT=NONE] -->
- <string name="summary_glasses_multi_device">This app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string>
-
- <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] -->
- <string name="summary_glasses_single_device">This app will be allowed to access these permissions on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></string>
+ <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile [CHAR LIMIT=NONE] -->
+ <string name="summary_glasses">This app will be allowed to access these permissions on your <xliff:g id="device_name" example="phone">%1$s</xliff:g></string>
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
@@ -97,9 +94,6 @@
<string name="profile_name_generic">device</string>
<!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] -->
- <string name="summary_generic_single_device">This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="device_name" example="My Watch">%1$s</xliff:g></string>
-
- <!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_generic">This app will be able to sync info, like the name of someone calling, between your phone and the chosen device</string>
<!-- ================= Buttons ================= -->
@@ -110,6 +104,9 @@
<!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
<string name="consent_no">Don\u2019t allow</string>
+ <!-- Cancel button for the device chooser dialog [CHAR LIMIT=30] -->
+ <string name="consent_cancel">Cancel</string>
+
<!-- Back button for the helper consent dialog [CHAR LIMIT=30] -->
<string name="consent_back">Back</string>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index e85190b..222877b 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -69,11 +69,13 @@
<style name="PositiveButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
- <item name="android:layout_width">300dp</item>
- <item name="android:layout_height">56dp</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">2dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
+ <item name="android:layout_marginStart">32dp</item>
+ <item name="android:layout_marginEnd">32dp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
<item name="android:background">@drawable/btn_positive_bottom</item>
@@ -81,11 +83,13 @@
<style name="NegativeButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
- <item name="android:layout_width">300dp</item>
- <item name="android:layout_height">56dp</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">2dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
+ <item name="android:layout_marginStart">32dp</item>
+ <item name="android:layout_marginEnd">32dp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
<item name="android:layout_marginTop">4dp</item>
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 4154029..97016f5 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -27,10 +27,8 @@
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
-import static com.android.companiondevicemanager.CompanionDeviceResources.MULTI_DEVICES_SUMMARIES;
import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TYPES;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME_MULTI;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICON;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUMMARIES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
@@ -121,6 +119,9 @@
private IAssociationRequestCallback mAppCallback;
private ResultReceiver mCdmServiceReceiver;
+ // Present for application's name.
+ private CharSequence mAppLabel;
+
// Always present widgets.
private TextView mTitle;
private TextView mSummary;
@@ -165,8 +166,7 @@
private @Nullable RecyclerView mDeviceListRecyclerView;
private @Nullable DeviceListAdapter mDeviceAdapter;
-
- // The recycler view is only shown for selfManaged and singleDevice association request.
+ // The recycler view is shown for non-null profile association request.
private @Nullable RecyclerView mPermissionListRecyclerView;
private @Nullable PermissionListAdapter mPermissionListAdapter;
@@ -178,8 +178,6 @@
// onActivityResult() after the association is created.
private @Nullable DeviceFilterPair<?> mSelectedDevice;
- private @Nullable List<Integer> mPermissionTypes;
-
private LinearLayoutManager mPermissionsLayoutManager = new LinearLayoutManager(this);
@Override
@@ -302,6 +300,8 @@
setContentView(R.layout.activity_confirmation);
+ mAppLabel = appLabel;
+
mConstraintList = findViewById(R.id.constraint_list);
mAssociationConfirmationDialog = findViewById(R.id.association_confirmation);
mVendorHeader = findViewById(R.id.vendor_header);
@@ -322,7 +322,6 @@
mMultipleDeviceSpinner = findViewById(R.id.spinner_multiple_device);
mSingleDeviceSpinner = findViewById(R.id.spinner_single_device);
- mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
mPermissionListRecyclerView = findViewById(R.id.permission_list);
mPermissionListAdapter = new PermissionListAdapter(this);
@@ -468,8 +467,6 @@
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
- mPermissionTypes = new ArrayList<>();
-
try {
vendorIcon = getVendorHeaderIcon(this, packageName, userId);
vendorName = getVendorHeaderName(this, packageName, userId);
@@ -486,17 +483,13 @@
}
title = getHtmlFromResources(this, TITLES.get(deviceProfile), deviceName);
- mPermissionTypes.addAll(PERMISSION_TYPES.get(deviceProfile));
+ setupPermissionList(deviceProfile);
// Summary is not needed for selfManaged dialog.
mSummary.setVisibility(View.GONE);
-
- setupPermissionList();
-
mTitle.setText(title);
mVendorHeaderName.setText(vendorName);
mVendorHeader.setVisibility(View.VISIBLE);
- mVendorHeader.setVisibility(View.VISIBLE);
mProfileIcon.setVisibility(View.GONE);
mDeviceListRecyclerView.setVisibility(View.GONE);
// Top and bottom borders should be gone for selfManaged dialog.
@@ -509,7 +502,9 @@
final String deviceProfile = mRequest.getDeviceProfile();
- mPermissionTypes = new ArrayList<>();
+ if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
+ throw new RuntimeException("Unsupported profile " + deviceProfile);
+ }
CompanionDeviceDiscoveryService.getScanResult().observe(this,
deviceFilterPairs -> updateSingleDeviceUi(
@@ -529,75 +524,40 @@
if (deviceFilterPairs.isEmpty()) return;
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
- // No need to show user consent dialog if it is a singleDevice
- // and isSkipPrompt(true) AssociationRequest.
- // See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
- if (mRequest.isSkipPrompt()) {
- mSingleDeviceSpinner.setVisibility(View.GONE);
- onUserSelectedDevice(mSelectedDevice);
- return;
- }
- final String deviceName = mSelectedDevice.getDisplayName();
- final Spanned title;
- final Spanned summary;
- final Drawable profileIcon;
+ final Drawable profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
- if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
- throw new RuntimeException("Unsupported profile " + deviceProfile);
- }
+ updatePermissionUi();
- if (deviceProfile == null) {
- summary = getHtmlFromResources(this, SUMMARIES.get(null), deviceName);
- mConstraintList.setVisibility(View.GONE);
- } else {
- summary = getHtmlFromResources(
- this, SUMMARIES.get(deviceProfile), getString(R.string.device_type));
- mPermissionTypes.addAll(PERMISSION_TYPES.get(deviceProfile));
- setupPermissionList();
- }
-
- title = getHtmlFromResources(this, TITLES.get(deviceProfile), appLabel, deviceName);
- profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
-
- mTitle.setText(title);
- mSummary.setText(summary);
mProfileIcon.setImageDrawable(profileIcon);
- mSingleDeviceSpinner.setVisibility(View.GONE);
mAssociationConfirmationDialog.setVisibility(View.VISIBLE);
+ mSingleDeviceSpinner.setVisibility(View.GONE);
}
private void initUiForMultipleDevices(CharSequence appLabel) {
if (DEBUG) Log.i(TAG, "initUiFor_MultipleDevices()");
- final String deviceProfile = mRequest.getDeviceProfile();
-
- final String profileName;
- final String profileNameMulti;
- final Spanned summary;
final Drawable profileIcon;
- final int summaryResourceId;
+ final Spanned title;
+ final String deviceProfile = mRequest.getDeviceProfile();
if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
- profileName = getString(PROFILES_NAME.get(deviceProfile));
- profileNameMulti = getString(PROFILES_NAME_MULTI.get(deviceProfile));
profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
- summaryResourceId = MULTI_DEVICES_SUMMARIES.get(deviceProfile);
if (deviceProfile == null) {
- summary = getHtmlFromResources(this, summaryResourceId);
+ title = getHtmlFromResources(this, R.string.chooser_title_non_profile, appLabel);
+ mButtonNotAllowMultipleDevices.setText(R.string.consent_no);
} else {
- summary = getHtmlFromResources(this, summaryResourceId, profileName, appLabel);
+ title = getHtmlFromResources(this,
+ R.string.chooser_title, getString(PROFILES_NAME.get(deviceProfile)));
}
- final Spanned title = getHtmlFromResources(
- this, R.string.chooser_title, profileNameMulti, appLabel);
+ mDeviceAdapter = new DeviceListAdapter(this, this::onDeviceClicked);
mTitle.setText(title);
- mSummary.setText(summary);
mProfileIcon.setImageDrawable(profileIcon);
mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
@@ -613,6 +573,7 @@
mDeviceAdapter.setDevices(deviceFilterPairs);
});
+ mSummary.setVisibility(View.GONE);
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
mButtonNotAllow.setVisibility(View.GONE);
@@ -623,11 +584,9 @@
mMultipleDeviceSpinner.setVisibility(View.VISIBLE);
}
- private void onListItemClick(int position) {
- if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
-
+ private void onDeviceClicked(int position) {
final DeviceFilterPair<?> selectedDevice = mDeviceAdapter.getItem(position);
-
+ // To prevent double tap on the selected device.
if (mSelectedDevice != null) {
if (DEBUG) Log.w(TAG, "Already selected.");
return;
@@ -637,7 +596,47 @@
mSelectedDevice = requireNonNull(selectedDevice);
- onUserSelectedDevice(selectedDevice);
+ Log.d(TAG, "onDeviceClicked(): " + mSelectedDevice.toShortString());
+
+ updatePermissionUi();
+
+ mSummary.setVisibility(View.VISIBLE);
+ mButtonAllow.setVisibility(View.VISIBLE);
+ mButtonNotAllow.setVisibility(View.VISIBLE);
+ mDeviceListRecyclerView.setVisibility(View.GONE);
+ mNotAllowMultipleDevicesLayout.setVisibility(View.GONE);
+ }
+
+ private void updatePermissionUi() {
+ final String deviceProfile = mRequest.getDeviceProfile();
+ final int summaryResourceId = SUMMARIES.get(deviceProfile);
+ final String remoteDeviceName = mSelectedDevice.getDisplayName();
+ final Spanned title = getHtmlFromResources(
+ this, TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
+ final Spanned summary;
+
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
+ if (deviceProfile == null && mRequest.isSingleDevice()) {
+ summary = getHtmlFromResources(this, summaryResourceId, remoteDeviceName);
+ mConstraintList.setVisibility(View.GONE);
+ } else if (deviceProfile == null) {
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ } else {
+ summary = getHtmlFromResources(
+ this, summaryResourceId, getString(R.string.device_type));
+ setupPermissionList(deviceProfile);
+ }
+
+ mTitle.setText(title);
+ mSummary.setText(summary);
}
private void onPositiveButtonClick(View v) {
@@ -680,8 +679,9 @@
// initiate the layoutManager for the recyclerview, add listeners for monitoring the scrolling
// and when mPermissionListRecyclerView is fully populated.
// Lastly, disable the Allow and Don't allow buttons.
- private void setupPermissionList() {
- mPermissionListAdapter.setPermissionType(mPermissionTypes);
+ private void setupPermissionList(String deviceProfile) {
+ final List<Integer> permissionTypes = new ArrayList<>(PERMISSION_TYPES.get(deviceProfile));
+ mPermissionListAdapter.setPermissionType(permissionTypes);
mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
mPermissionListRecyclerView.setLayoutManager(mPermissionsLayoutManager);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
index 7aed139..060c032 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
@@ -86,21 +86,11 @@
static final Map<String, Integer> SUMMARIES;
static {
final Map<String, Integer> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch_single_device);
- map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses_single_device);
- map.put(null, R.string.summary_generic_single_device);
-
- SUMMARIES = unmodifiableMap(map);
- }
-
- static final Map<String, Integer> MULTI_DEVICES_SUMMARIES;
- static {
- final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
- map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses_multi_device);
+ map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
map.put(null, R.string.summary_generic);
- MULTI_DEVICES_SUMMARIES = unmodifiableMap(map);
+ SUMMARIES = unmodifiableMap(map);
}
static final Map<String, Integer> PROFILES_NAME;
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index b265a42..738354f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -423,7 +423,10 @@
Log.e(TAG, "It's already running in normal system.");
return;
}
-
+ if (mDynSystem.getActiveDsuSlot().endsWith(".lock")) {
+ Log.e(TAG, "Ignore the reboot intent for a locked DSU slot");
+ return;
+ }
if (!mDynSystem.setEnable(/* enable = */ false, /* oneShot = */ false)) {
Log.e(TAG, "Failed to disable DynamicSystem.");
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index 2b38b4c..8e0cf89 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -34,11 +34,11 @@
/**
* The repository to load the App List data.
*/
-internal interface AppListRepository {
+interface AppListRepository {
/** Loads the list of [ApplicationInfo]. */
suspend fun loadApps(
userId: Int,
- showInstantApps: Boolean = false,
+ loadInstantApps: Boolean = false,
matchAnyUserForAdmin: Boolean = false,
): List<ApplicationInfo>
@@ -50,6 +50,9 @@
/** Gets the system app package names. */
fun getSystemPackageNamesBlocking(userId: Int): Set<String>
+
+ /** Loads the list of [ApplicationInfo], and filter base on `isSystemApp`. */
+ suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean): List<ApplicationInfo>
}
/**
@@ -62,13 +65,13 @@
AppListRepositoryImpl(context).getSystemPackageNamesBlocking(userId)
}
-internal class AppListRepositoryImpl(private val context: Context) : AppListRepository {
+class AppListRepositoryImpl(private val context: Context) : AppListRepository {
private val packageManager = context.packageManager
private val userManager = context.userManager
override suspend fun loadApps(
userId: Int,
- showInstantApps: Boolean,
+ loadInstantApps: Boolean,
matchAnyUserForAdmin: Boolean,
): List<ApplicationInfo> = coroutineScope {
val hiddenSystemModulesDeferred = async {
@@ -86,7 +89,7 @@
val hiddenSystemModules = hiddenSystemModulesDeferred.await()
val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
installedApplicationsAsUser.filter { app ->
- app.isInAppList(showInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+ app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
}
}
@@ -136,17 +139,17 @@
): Flow<(app: ApplicationInfo) -> Boolean> =
userIdFlow.combine(showSystemFlow, ::showSystemPredicate)
- override fun getSystemPackageNamesBlocking(userId: Int) =
- runBlocking { getSystemPackageNames(userId) }
+ override fun getSystemPackageNamesBlocking(userId: Int) = runBlocking {
+ loadAndFilterApps(userId = userId, isSystemApp = true).map { it.packageName }.toSet()
+ }
- private suspend fun getSystemPackageNames(userId: Int): Set<String> =
- coroutineScope {
- val loadAppsDeferred = async { loadApps(userId) }
- val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId)
- val showSystemPredicate =
- { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) }
- loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet()
+ override suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean) = coroutineScope {
+ val loadAppsDeferred = async { loadApps(userId) }
+ val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId)
+ loadAppsDeferred.await().filter { app ->
+ isSystemApp(app, homeOrLauncherPackages) == isSystemApp
}
+ }
private suspend fun showSystemPredicate(
userId: Int,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index 302f780..375ed60 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -108,7 +108,7 @@
val appList = repository.loadApps(
userId = ADMIN_USER_ID,
- showInstantApps = false,
+ loadInstantApps = false,
)
assertThat(appList).containsExactly(NORMAL_APP)
@@ -120,7 +120,7 @@
val appList = repository.loadApps(
userId = ADMIN_USER_ID,
- showInstantApps = true,
+ loadInstantApps = true,
)
assertThat(appList).containsExactly(NORMAL_APP, INSTANT_APP)
@@ -325,6 +325,21 @@
assertThat(systemPackageNames).containsExactly(SYSTEM_APP.packageName)
}
+ @Test
+ fun loadAndFilterApps_loadNonSystemApp_returnExpectedValues() = runTest {
+ mockInstalledApplications(
+ apps = listOf(
+ NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP
+ ),
+ userId = ADMIN_USER_ID,
+ )
+
+ val appList = repository.loadAndFilterApps(userId = ADMIN_USER_ID, isSystemApp = false)
+
+ assertThat(appList)
+ .containsExactly(NORMAL_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP)
+ }
+
private suspend fun getShowSystemPredicate(showSystem: Boolean) =
repository.showSystemPredicate(
userIdFlow = flowOf(ADMIN_USER_ID),
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
index 6889e5d..9b22497 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
@@ -87,7 +87,7 @@
private object FakeAppListRepository : AppListRepository {
override suspend fun loadApps(
userId: Int,
- showInstantApps: Boolean,
+ loadInstantApps: Boolean,
matchAnyUserForAdmin: Boolean,
) = listOf(APP)
@@ -97,6 +97,9 @@
): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true }
override fun getSystemPackageNamesBlocking(userId: Int): Set<String> = emptySet()
+
+ override suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean) =
+ emptyList<ApplicationInfo>()
}
private object FakeAppRepository : AppRepository {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 873b434..dd8eb3b 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -590,6 +590,7 @@
Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS,
Settings.Global.AUTO_REVOKE_PARAMETERS,
Settings.Global.ENABLE_RADIO_BUG_DETECTION,
+ Settings.Global.REPAIR_MODE_ACTIVE,
Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD,
Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD,
Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT,
@@ -724,6 +725,7 @@
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
Settings.Secure.CONTENT_CAPTURE_ENABLED,
Settings.Secure.DEFAULT_INPUT_METHOD,
+ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
Settings.Secure.DEVICE_PAIRED,
Settings.Secure.DIALER_DEFAULT_APPLICATION,
Settings.Secure.DISABLED_PRINT_SERVICES,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fe90caf..476c820 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -176,6 +176,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
+ <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<!-- Assist -->
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
@@ -451,12 +452,14 @@
android:noHistory="true" />
<service android:name=".screenshot.appclips.AppClipsScreenshotHelperService"
- android:permission="com.android.systemui.permission.SELF"
- android:exported="false" />
+ android:exported="false"
+ android:singleUser="true"
+ android:permission="com.android.systemui.permission.SELF" />
<service android:name=".screenshot.appclips.AppClipsService"
- android:permission="android.permission.LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE"
- android:exported="true" />
+ android:exported="true"
+ android:singleUser="true"
+ android:permission="android.permission.LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE" />
<service android:name=".screenrecord.RecordingService"
android:foregroundServiceType="systemExempted"/>
@@ -990,6 +993,11 @@
<service android:name=".notetask.NoteTaskControllerUpdateService" />
+ <service android:name=".notetask.NoteTaskBubblesController$NoteTaskBubblesService"
+ android:exported="false"
+ android:singleUser="true"
+ android:permission="com.android.systemui.permission.SELF" />
+
<activity
android:name=".notetask.shortcut.LaunchNoteTaskActivity"
android:exported="true"
@@ -1003,16 +1011,6 @@
</intent-filter>
</activity>
- <!-- LaunchNoteTaskManagedProfileProxyActivity MUST NOT be exported because it allows caller
- to specify an Android user when launching the default notes app. -->
- <activity
- android:name=".notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity"
- android:exported="false"
- android:enabled="true"
- android:excludeFromRecents="true"
- android:resizeableActivity="false"
- android:theme="@android:style/Theme.NoDisplay" />
-
<activity
android:name=".notetask.LaunchNotesRoleSettingsTrampolineActivity"
android:exported="true"
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
index 8fe1f48..4fe9f89 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Easings.kt
@@ -27,37 +27,52 @@
object Easings {
/** The standard interpolator that should be used on every normal animation */
- val StandardEasing = fromInterpolator(InterpolatorsAndroidX.STANDARD)
+ val Standard = fromInterpolator(InterpolatorsAndroidX.STANDARD)
/**
* The standard accelerating interpolator that should be used on every regular movement of
* content that is disappearing e.g. when moving off screen.
*/
- val StandardAccelerateEasing = fromInterpolator(InterpolatorsAndroidX.STANDARD_ACCELERATE)
+ val StandardAccelerate = fromInterpolator(InterpolatorsAndroidX.STANDARD_ACCELERATE)
/**
* The standard decelerating interpolator that should be used on every regular movement of
* content that is appearing e.g. when coming from off screen.
*/
- val StandardDecelerateEasing = fromInterpolator(InterpolatorsAndroidX.STANDARD_DECELERATE)
+ val StandardDecelerate = fromInterpolator(InterpolatorsAndroidX.STANDARD_DECELERATE)
/** The default emphasized interpolator. Used for hero / emphasized movement of content. */
- val EmphasizedEasing = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED)
+ val Emphasized = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED)
/**
* The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
* is disappearing e.g. when moving off screen.
*/
- val EmphasizedAccelerateEasing = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED_ACCELERATE)
+ val EmphasizedAccelerate = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED_ACCELERATE)
/**
* The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
* is appearing e.g. when coming from off screen
*/
- val EmphasizedDecelerateEasing = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED_DECELERATE)
+ val EmphasizedDecelerate = fromInterpolator(InterpolatorsAndroidX.EMPHASIZED_DECELERATE)
/** The linear interpolator. */
- val LinearEasing = fromInterpolator(InterpolatorsAndroidX.LINEAR)
+ val Linear = fromInterpolator(InterpolatorsAndroidX.LINEAR)
+
+ /** The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN. */
+ val Legacy = fromInterpolator(InterpolatorsAndroidX.LEGACY)
+
+ /**
+ * The default legacy accelerating interpolator as defined in Material 1. Also known as
+ * FAST_OUT_LINEAR_IN.
+ */
+ val LegacyAccelerate = fromInterpolator(InterpolatorsAndroidX.LEGACY_ACCELERATE)
+
+ /**
+ * T The default legacy decelerating interpolator as defined in Material 1. Also known as
+ * LINEAR_OUT_SLOW_IN.
+ */
+ val LegacyDecelerate = fromInterpolator(InterpolatorsAndroidX.LEGACY_DECELERATE)
private fun fromInterpolator(source: Interpolator) = Easing { x -> source.getInterpolation(x) }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index 8844114..b3d2e35 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -131,7 +131,7 @@
animationSpec =
tween(
durationMillis = SELECTED_DOT_REACTION_ANIMATION_DURATION_MS,
- easing = Easings.StandardAccelerateEasing,
+ easing = Easings.StandardAccelerate,
),
)
} else {
@@ -140,7 +140,7 @@
animationSpec =
tween(
durationMillis = SELECTED_DOT_RETRACT_ANIMATION_DURATION_MS,
- easing = Easings.StandardDecelerateEasing,
+ easing = Easings.StandardDecelerate,
),
)
}
@@ -333,7 +333,7 @@
FAILURE_ANIMATION_DOT_SHRINK_ANIMATION_DURATION_MS,
delayMillis =
rowIndex * FAILURE_ANIMATION_DOT_SHRINK_STAGGER_DELAY_MS,
- easing = Easings.LinearEasing,
+ easing = Easings.Linear,
),
)
@@ -343,7 +343,7 @@
tween(
durationMillis =
FAILURE_ANIMATION_DOT_REVERT_ANIMATION_DURATION,
- easing = Easings.StandardEasing,
+ easing = Easings.Standard,
),
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 968e5ab..f801434 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -19,23 +19,19 @@
package com.android.systemui.bouncer.ui.composable
import android.view.HapticFeedbackConstants
-import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.AnimationSpec
-import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.MutableTransitionState
+import androidx.compose.animation.core.Transition
+import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.keyframes
+import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.scaleIn
-import androidx.compose.animation.scaleOut
-import androidx.compose.animation.slideInHorizontally
-import androidx.compose.animation.slideOutHorizontally
-import androidx.compose.foundation.background
+import androidx.compose.animation.core.updateTransition
+import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -43,35 +39,40 @@
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
import com.android.systemui.R
+import com.android.systemui.bouncer.ui.viewmodel.EnteredKey
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.compose.modifiers.thenIf
-import kotlin.math.max
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
import kotlinx.coroutines.async
@@ -86,8 +87,6 @@
// Report that the UI is shown to let the view-model run some logic.
LaunchedEffect(Unit) { viewModel.onShown() }
- // The length of the PIN input received so far, so we know how many dots to render.
- val pinLength: Pair<Int, Int> by viewModel.pinLengths.collectAsState()
val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
@@ -103,30 +102,7 @@
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier,
) {
- Row(
- horizontalArrangement = Arrangement.spacedBy(12.dp),
- modifier = Modifier.heightIn(min = 16.dp).animateContentSize(),
- ) {
- // TODO(b/281871687): add support for dot shapes.
- val (previousPinLength, currentPinLength) = pinLength
- val dotCount = max(previousPinLength, currentPinLength) + 1
- repeat(dotCount) { index ->
- AnimatedVisibility(
- visible = index < currentPinLength,
- enter = fadeIn() + scaleIn() + slideInHorizontally(),
- exit = fadeOut() + scaleOut() + slideOutHorizontally(),
- ) {
- Box(
- modifier =
- Modifier.size(16.dp)
- .background(
- MaterialTheme.colorScheme.onSurfaceVariant,
- CircleShape,
- )
- )
- }
- }
- }
+ PinInputDisplay(viewModel)
Spacer(Modifier.height(100.dp))
@@ -187,6 +163,148 @@
}
@Composable
+private fun PinInputDisplay(viewModel: PinBouncerViewModel) {
+ val currentPinEntries: List<EnteredKey> by viewModel.pinEntries.collectAsState()
+
+ // visiblePinEntries keeps pins removed from currentPinEntries in the composition until their
+ // disappear-animation completed. The list is sorted by the natural ordering of EnteredKey,
+ // which is guaranteed to produce the original edit order, since the model only modifies entries
+ // at the end.
+ val visiblePinEntries = remember { SnapshotStateList<EnteredKey>() }
+ currentPinEntries.forEach {
+ val index = visiblePinEntries.binarySearch(it)
+ if (index < 0) {
+ val insertionPoint = -(index + 1)
+ visiblePinEntries.add(insertionPoint, it)
+ }
+ }
+
+ Row(
+ modifier =
+ Modifier.heightIn(min = entryShapeSize)
+ // Pins overflowing horizontally should still be shown as scrolling.
+ .wrapContentSize(unbounded = true),
+ ) {
+ visiblePinEntries.forEachIndexed { index, entry ->
+ key(entry) {
+ val visibility = remember {
+ MutableTransitionState<EntryVisibility>(EntryVisibility.Hidden)
+ }
+ visibility.targetState =
+ when {
+ currentPinEntries.isEmpty() && visiblePinEntries.size > 1 ->
+ EntryVisibility.BulkHidden(index, visiblePinEntries.size)
+ currentPinEntries.contains(entry) -> EntryVisibility.Shown
+ else -> EntryVisibility.Hidden
+ }
+
+ ObscuredInputEntry(updateTransition(visibility, label = "Pin Entry $entry"))
+
+ LaunchedEffect(entry) {
+ // Remove entry from visiblePinEntries once the hide transition completed.
+ snapshotFlow {
+ visibility.currentState == visibility.targetState &&
+ visibility.targetState != EntryVisibility.Shown
+ }
+ .collect { isRemoved ->
+ if (isRemoved) {
+ visiblePinEntries.remove(entry)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+private sealed class EntryVisibility {
+ object Shown : EntryVisibility()
+
+ object Hidden : EntryVisibility()
+
+ /**
+ * Same as [Hidden], but applies when multiple entries are hidden simultaneously, without
+ * collapsing during the hide.
+ */
+ data class BulkHidden(val staggerIndex: Int, val totalEntryCount: Int) : EntryVisibility()
+}
+
+@Composable
+private fun ObscuredInputEntry(transition: Transition<EntryVisibility>) {
+ // spec: http://shortn/_DEhE3Xl2bi
+ val shapePadding = 6.dp
+ val shapeOvershootSize = 22.dp
+ val dismissStaggerDelayMs = 33
+ val dismissDurationMs = 450
+ val expansionDurationMs = 250
+ val shapeExpandDurationMs = 83
+ val shapeRetractDurationMs = 167
+ val shapeCollapseDurationMs = 200
+
+ val animatedEntryWidth by
+ transition.animateDp(
+ transitionSpec = {
+ when (val target = targetState) {
+ is EntryVisibility.BulkHidden ->
+ // only collapse horizontal space once all entries are removed
+ snap(dismissDurationMs + dismissStaggerDelayMs * target.totalEntryCount)
+ else -> tween(expansionDurationMs, easing = Easings.Standard)
+ }
+ },
+ label = "entry space"
+ ) { state ->
+ if (state == EntryVisibility.Shown) entryShapeSize + (shapePadding * 2) else 0.dp
+ }
+
+ val animatedShapeSize by
+ transition.animateDp(
+ transitionSpec = {
+ when {
+ EntryVisibility.Hidden isTransitioningTo EntryVisibility.Shown ->
+ keyframes {
+ durationMillis = shapeExpandDurationMs + shapeRetractDurationMs
+ 0.dp at 0 with Easings.Linear
+ shapeOvershootSize at shapeExpandDurationMs with Easings.Legacy
+ }
+ targetState is EntryVisibility.BulkHidden -> {
+ val target = targetState as EntryVisibility.BulkHidden
+ tween(
+ dismissDurationMs,
+ delayMillis = target.staggerIndex * dismissStaggerDelayMs,
+ easing = Easings.Legacy,
+ )
+ }
+ else -> tween(shapeCollapseDurationMs, easing = Easings.StandardDecelerate)
+ }
+ },
+ label = "shape size"
+ ) { state ->
+ when (state) {
+ EntryVisibility.Shown -> entryShapeSize
+ else -> 0.dp
+ }
+ }
+
+ val dotColor = MaterialTheme.colorScheme.onSurfaceVariant
+ Layout(
+ content = {
+ // TODO(b/282730134): add support for dot shapes.
+ Canvas(Modifier) { drawCircle(dotColor) }
+ }
+ ) { measurables, _ ->
+ val shapeSizePx = animatedShapeSize.roundToPx()
+ val placeable = measurables.single().measure(Constraints.fixed(shapeSizePx, shapeSizePx))
+
+ layout(animatedEntryWidth.roundToPx(), entryShapeSize.roundToPx()) {
+ placeable.place(
+ ((animatedEntryWidth - animatedShapeSize) / 2f).roundToPx(),
+ ((entryShapeSize - animatedShapeSize) / 2f).roundToPx()
+ )
+ }
+ }
+}
+
+@Composable
private fun PinDigit(
digit: Int,
contentColor: Color,
@@ -310,11 +428,13 @@
// TODO(b/282730134): implement.
}
+private val entryShapeSize = 16.dp
+
private val pinButtonSize = 84.dp
// Pin button motion spec: http://shortn/_9TTIG6SoEa
private val pinButtonPressedDuration = 100.milliseconds
-private val pinButtonPressedEasing = LinearEasing
+private val pinButtonPressedEasing = Easings.Linear
private val pinButtonHoldTime = 33.milliseconds
private val pinButtonReleasedDuration = 420.milliseconds
-private val pinButtonReleasedEasing = Easings.StandardEasing
+private val pinButtonReleasedEasing = Easings.Standard
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index a3a7135..66c57fc 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -23,7 +23,7 @@
android:outlineProvider="none" >
<LinearLayout
- android:id="@+id/keyguard_indication_area"
+ android:id="@id/keyguard_indication_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
@@ -31,7 +31,7 @@
android:orientation="vertical">
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_text"
+ android:id="@id/keyguard_indication_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
@@ -41,13 +41,12 @@
android:accessibilityLiveRegion="polite"/>
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_text_bottom"
+ android:id="@id/keyguard_indication_text_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
- android:minHeight="48dp"
+ android:minHeight="@dimen/keyguard_indication_text_min_height"
android:layout_gravity="center_horizontal"
- android:layout_centerHorizontal="true"
android:paddingStart="@dimen/keyguard_indication_text_padding"
android:paddingEnd="@dimen/keyguard_indication_text_padding"
android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
diff --git a/packages/SystemUI/res/layout/scene_window_root.xml b/packages/SystemUI/res/layout/scene_window_root.xml
new file mode 100644
index 0000000..0dcd15b
--- /dev/null
+++ b/packages/SystemUI/res/layout/scene_window_root.xml
@@ -0,0 +1,32 @@
+<?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.
+*/
+-->
+
+<!-- The root view of the scene window. -->
+<com.android.systemui.scene.ui.view.SceneWindowRootView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/scene_window_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+
+ <include layout="@layout/super_notification_shade"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</com.android.systemui.scene.ui.view.SceneWindowRootView>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index d9fe949..6601e63 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -21,6 +21,7 @@
<com.android.systemui.shade.NotificationShadeWindowView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/legacy_window_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
@@ -69,6 +70,12 @@
android:layout_height="match_parent"
android:visibility="invisible" />
+ <!-- Root for all keyguard content. It was previously located within the shade. -->
+ <com.android.systemui.keyguard.ui.view.KeyguardRootView
+ android:id="@id/keyguard_root_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
<include layout="@layout/brightness_mirror_container" />
<com.android.systemui.scrim.ScrimView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f7f45e2..bbf3101b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Vergroot die hele skerm"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 17f7d5a..41feb8d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ሙሉ ገፅ እይታን ያጉሉ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"የማጉያ ቅንብሮችን ክፈት"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 71266fb..2c495e8 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"تكبير الشاشة كلها"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"فتح إعدادات التكبير"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 02637642..e9fd768 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"পূৰ্ণ স্ক্ৰীন বিবৰ্ধন কৰক"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বিবৰ্ধন কৰাৰ ছেটিং খোলক"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 047323f..e2bc20d 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 5575274..02a3f09 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećajte ceo ekran"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 1576fb5..5a4aca7 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Павялічыць увесь экран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Адкрыць налады павелічэння"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ec85234..c9dca7b 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличаване на целия екран"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"Плъзнете ъгъла за преоразмеряване"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Разрешаване на диагонално превъртане"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Преоразмеряване"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 3335c3d..a8b32fe 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"সম্পূর্ণ স্ক্রিন বড় করে দেখা"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বড় করে দেখার সেটিংস খুলুন"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4d6d78c..0cd88aa 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećavanje prikaza preko cijelog ekrana"</string>
<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 povećavanja"</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>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a998436..af9f55c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Amplia la pantalla completa"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4530fb7..cafa52d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zvětšit celou obrazovku"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 38eda88..2161751 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstør hele skærmen"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b6b896f..0f7a76e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ganzen Bildschirm vergrößern"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 073e9f4..aa93d4a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Μεγέθυνση πλήρους οθόνης"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Μεγέθυνση μέρους της οθόνης"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Άνοιγμα ρυθμίσεων μεγιστοποίησης"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 61c15e2..df0163b 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d442f6a..c3fd9b4 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (3783056044917913453) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognized. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognized. Press the unlock icon to continue."</string>
@@ -860,6 +859,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 61c15e2..df0163b 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 61c15e2..df0163b 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index cbc9538..a93c6c6 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (3783056044917913453) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognized. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognized. Press the unlock icon to continue."</string>
@@ -860,6 +859,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4855959..dfa47b562 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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">"Desplazamiento en diagonal"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Cambiar tamaño"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 23a2d13..dcacd75 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2328b7b..619c5fa 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Täisekraani suurendamine"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 269df8a..e37541e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Handitu pantaila osoa"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1e0189c..875c520 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"درشتنمایی تمامصفحه"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"باز کردن تنظیمات درشتنمایی"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2878c66ce..f936085 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Koko näytön suurennus"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 0e7a0bd..742e4a0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -884,6 +884,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 21176b3..b6d0bee 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir tout l\'écran"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index fc3d033..5719e3e 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c5b3d2e4..368498d 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"પૂર્ણ સ્ક્રીનને મોટી કરો"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"મોટા કરવાના સેટિંગ ખોલો"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index fb4de70..1edb9f7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -290,7 +290,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> उपयोग किया गया"</string>
<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_label" msgid="6440531507319809121">"वर्क ऐप्लिकेशन"</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>
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फ़ुल स्क्रीन को ज़ूम करें"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ज़ूम करने की सुविधा वाली सेटिंग खोलें"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9cb3fe8..a61ec57 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povećajte cijeli zaslon"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 36e4cd2..027459b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"A teljes képernyő felnagyítása"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 57b3033..68ab894 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Խոշորացնել ամբողջ էկրանը"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"Քաշեք անկյունը՝ չափը փոխելու համար"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Թույլատրել անկյունագծով ոլորումը"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"Փոխել չափը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 4ece767..c36f19b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Memperbesar tampilan layar penuh"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 29494ff..84267c1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Stækka allan skjáinn"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f9b329e..f79dc0d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ingrandisci l\'intero schermo"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6cf8ffa..18291d3 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"הגדלה של המסך המלא"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"פתיחת הגדרות ההגדלה"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a515e49..6643539 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"画面全体を拡大します"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"サイズを変更するには角をドラッグ"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"斜めスクロールを許可"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"サイズ変更"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d37dfaf..268c666 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"გაადიდეთ სრულ ეკრანზე"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"ჩავლებით გადაიტანეთ კუთხე ზომის შესაცვლელად"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"დიაგონალური გადაადგილების დაშვება"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ზომის შეცვლა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 64ceefd..db64dd4 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толық экранды ұлғайту"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ұлғайту параметрлерін ашу"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 43de595..f241f5e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ពង្រីកពេញអេក្រង់"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"បើកការកំណត់ការពង្រីក"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 2ea1500..17fbd9a 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಿಗ್ಗಿಸಿ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ಹಿಗ್ಗಿಸುವಿಕೆ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
@@ -912,7 +914,7 @@
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗಿಲ್ಲ"</string>
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ಇತರ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ಮರುಹೊಂದಿಸಿ"</string>
- <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ಕಂಟ್ರೋಲ್ಗಳನ್ನು ಸೇರಿಸಿ"</string>
+ <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ಎಡಿಟ್ ಮಾಡುವಿಕೆಗೆ ಹಿಂತಿರುಗಿ"</string>
<string name="controls_favorite_load_error" msgid="5126216176144877419">"ನಿಯಂತ್ರಣಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ಆ್ಯಪ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಬದಲಾಗಿಲ್ಲ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು <xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"ಹೊಂದಾಣಿಕೆಯ ನಿಯಂತ್ರಣಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9459744..e15b0f5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"확대 설정 열기"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index c5c448e..ac8d3776 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толук экранда ачуу"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Чоңойтуу параметрлерин ачуу"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6078b7b..9f32469 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ຂະຫຍາຍເຕັມຈໍ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ເປີດການຕັ້ງຄ່າການຂະຫຍາຍ"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index bb569e3..aba50e6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Viso ekrano didinimas"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2acefea..9859c11 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Palielināt visu ekrānu"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b52af9b..5c7e0a5 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Зголемете го целиот екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголемувајте дел од екранот"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори поставки за зголемување"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index ddd34be..119563e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"സ്ക്രീൻ പൂർണ്ണമായും മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"മാഗ്നിഫിക്കേഷൻ ക്രമീകരണം തുറക്കുക"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index bb92324..61079ce 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Бүтэн дэлгэцийг томруулах"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Томруулах тохиргоог нээх"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8c6fafe..922457c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फुल स्क्रीन मॅग्निफाय करा"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"मॅग्निफिकेशन सेटिंग्ज उघडा"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index db4bff0..b41f4f2 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Besarkan skrin penuh"</string>
<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_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>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 36f6344..57fe997 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ဖန်သားပြင်အပြည့် ချဲ့သည်"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ချဲ့ခြင်း ဆက်တင်များ ဖွင့်ရန်"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 36bd3b4..3a84389 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstørr hele skjermen"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 98e0201..2394974 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"पूरै स्क्रिन जुम इन गर्नुहोस्"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"जुम इनसम्बन्धी सेटिङ खोल्नुहोस्"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 53f0853..4a2b0e0 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Volledig scherm vergroten"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index c33c8ba..5f0c529d 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ମ୍ୟାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ମାଗ୍ନିଫିକେସନ ସେଟିଂସ ଖୋଲନ୍ତୁ"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 281b11a..df6bceb 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਵੱਡਦਰਸ਼ੀ ਕਰੋ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ਸਕ੍ਰੀਨ ਦੇ ਹਿੱਸੇ ਨੂੰ ਵੱਡਾ ਕਰੋ"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8a9608f..bfd560e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Powiększanie pełnego ekranu"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4018433..72ae7e6 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 2d9c7d3..12631f1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar o ecrã inteiro"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4018433..72ae7e6 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 060f6d7..06fc16b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Mărește tot ecranul"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d6530fb..c00058b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличение всего экрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Открыть настройки увеличения"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a5c1a18..35bc66a 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"පූර්ණ තිරය විශාලනය කරන්න"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"විශාලන සැකසීම් විවෘත කරන්න"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e60dd5f..7727f38 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zväčšenie celej obrazovky"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index dcc34c4..43de611 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f851d30..296b150 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zmadho ekranin e plotë"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
@@ -907,7 +909,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Zhvendose te pozicioni <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrollet"</string>
<string name="controls_favorite_subtitle" msgid="5818709315630850796">"Zgjidh kontrollet e pajisjes për të pasur qasje me shpejtësi"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mbaje të shtypur dhe zvarrit për të risistemuar kontrollet"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mbaje shtypur dhe zvarrit për të riorganizuar kontrollet"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Të gjitha kontrollet u hoqën"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ndryshimet nuk u ruajtën"</string>
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Shiko aplikacionet e tjera"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 576cad0..29c7291 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увећајте цео екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори подешавања увећања"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8fe491b..4f7610e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Förstora hela skärmen"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index e359c01..a6c2a05 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Kuza skrini nzima"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 7dcd0fb..9ea0379 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"முழுத்திரையைப் பெரிதாக்கும்"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"பெரிதாக்கல் அமைப்புகளைத் திற"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
@@ -972,7 +974,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"நிலையைக் காட்ட முடியவில்லை"</string>
<string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுக"</string>
<string name="controls_menu_add_another_app" msgid="8661172304650786705">"ஆப்ஸைச் சேர்"</string>
<string name="controls_menu_remove" msgid="3006525275966023468">"ஆப்ஸை அகற்று"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"அவுட்புட்களைச் சேர்த்தல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 9680b3e..dc5d463 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ఫుల్ స్క్రీన్ను మ్యాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మ్యాగ్నిఫై చేయండి"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"మ్యాగ్నిఫికేషన్ సెట్టింగ్లను తెరవండి"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 93365fe..470c631 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ขยายเป็นเต็มหน้าจอ"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"ลากที่มุมเพื่อปรับขนาด"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"อนุญาตการเลื่อนแบบทแยงมุม"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"ปรับขนาด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fec9aad..ca5963e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"I-magnify ang buong screen"</string>
<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>
<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>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index b5201fe..33da71b 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekran büyütme"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index e7d7e2e..0105d1e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Збільшення всього екрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Відкрити налаштування збільшення"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a67cc5a..550181c 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"فُل اسکرین کو بڑا کریں"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"اسکرین کا حصہ بڑا کریں"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"میگنیفکیشن کی ترتیبات کھولیں"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 86dc332..5f75932 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ekranni toʻliq kattalashtirish"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e4073e4..fb2923b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Phóng to toàn màn hình"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index cde0536..717e5ab 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整个屏幕"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string>
<string name="magnification_open_settings_click_label" msgid="6151849212725923363">"打开放大功能设置"</string>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1504fce..21ec6ac 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大成個畫面"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許斜角捲動"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"調整大小"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1450588..c533d6a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -860,6 +860,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整個螢幕畫面"</string>
<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_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string>
<string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許沿對角線捲動"</string>
<string name="accessibility_resize" msgid="5733759136600611551">"調整大小"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 64bf21a..22dfd88 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -860,6 +860,8 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Khulisa isikrini esigcwele"</string>
<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>
+ <!-- no translation found for magnification_close_settings_click_label (4642477260651704517) -->
+ <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>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8d3ba36..50d33c6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -275,6 +275,9 @@
<!-- The padding at start and end of indication text shown on AOD -->
<dimen name="keyguard_indication_text_padding">16dp</dimen>
+ <!-- The min height on the indication text shown on AOD -->
+ <dimen name="keyguard_indication_text_min_height">48dp</dimen>
+
<!-- Shadows under the clock, date and other keyguard text fields -->
<dimen name="keyguard_shadow_radius">5</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e5c9461..d651a21 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -206,5 +206,9 @@
<!-- keyboard backlight indicator-->
<item type="id" name="backlight_icon" />
-</resources>
+ <item type="id" name="keyguard_root_view" />
+ <item type="id" name="keyguard_indication_area" />
+ <item type="id" name="keyguard_indication_text" />
+ <item type="id" name="keyguard_indication_text_bottom" />
+</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 67fdb4c..c619d46 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2390,6 +2390,8 @@
<string name="magnification_mode_switch_state_window">Magnify part of screen</string>
<!-- Click action label for magnification settings panel. [CHAR LIMIT=NONE] -->
<string name="magnification_open_settings_click_label">Open magnification settings</string>
+ <!-- Click action label for magnification settings panel. [CHAR LIMIT=NONE] -->
+ <string name="magnification_close_settings_click_label">Close magnification settings</string>
<!-- Label of the corner of a rectangle that you can tap and drag to resize the magnification area. [CHAR LIMIT=NONE] -->
<string name="magnification_drag_corner_to_resize">Drag corner to resize</string>
@@ -2971,9 +2973,11 @@
<xliff:g id="weather_condition" example="Partly cloudy">%1$s</xliff:g>, <xliff:g id="temperature" example="7°C">%2$s</xliff:g>
</string>
- <!-- TODO(b/259369672): Replace with final resource. -->
<!-- [CHAR LIMIT=30] Label used to open Note Task -->
- <string name="note_task_button_label">Notetaking</string>
+ <string name="note_task_button_label">Note-taking</string>
+
+ <!-- [CHAR LIMIT=25] Long label used by Note Task Shortcut -->
+ <string name="note_task_shortcut_long_label">Note-taking, <xliff:g id="note_taking_app" example="Note-taking App">%1$s</xliff:g></string>
<!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is broadcasting -->
<string name="broadcasting_description_is_broadcasting">Broadcasting</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 117cf78a..4b31498 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -48,7 +48,7 @@
*
* Normal gesture: DOWN, MOVE/POINTER_DOWN/POINTER_UP)*, UP or CANCLE
*/
- oneway void onStatusBarMotionEvent(in MotionEvent event) = 9;
+ oneway void onStatusBarTouchEvent(in MotionEvent event) = 9;
/**
* Proxies the assistant gesture's progress started from navigation bar.
@@ -125,5 +125,15 @@
*/
oneway void takeScreenshot(in ScreenshotRequest request) = 51;
- // Next id = 52
+ /**
+ * Dispatches trackpad status bar motion event to the notification shade. Currently these events
+ * are from the input monitor in {@link TouchInteractionService}. This is different from
+ * {@link #onStatusBarTouchEvent} above in that, this directly dispatches motion events to the
+ * notification shade, while {@link #onStatusBarTouchEvent} relies on setting the launcher
+ * window slippery to allow the frameworks to route those events after passing the initial
+ * threshold.
+ */
+ oneway void onStatusBarTrackpadEvent(in MotionEvent event) = 52;
+
+ // Next id = 53
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index 9a00447..0ca2f7a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -263,6 +263,8 @@
(colors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) !=
WallpaperColors.HINT_SUPPORTS_DARK_TEXT
)
+ if (DEBUG)
+ Log.d(TAG, "onColorsChanged() | region darkness = $regionDarkness for region $area")
updateForegroundColor()
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 8ea4c31a..84a2c25 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -15,18 +15,18 @@
*/
package com.android.keyguard
-import android.app.WallpaperManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Resources
import android.text.format.DateFormat
-import android.util.TypedValue
import android.util.Log
+import android.util.TypedValue
import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.view.ViewTreeObserver
+import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -99,6 +99,28 @@
if (!regionSamplingEnabled) {
updateColors()
+ } else {
+ clock?.let {
+ smallRegionSampler = createRegionSampler(
+ it.smallClock.view,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ isLockscreen = true,
+ ::updateColors
+ )?.apply { startRegionSampler() }
+
+ largeRegionSampler = createRegionSampler(
+ it.largeClock.view,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingEnabled,
+ isLockscreen = true,
+ ::updateColors
+ )?.apply { startRegionSampler() }
+
+ updateColors()
+ }
}
updateFontSizes()
updateTimeListeners()
@@ -110,8 +132,25 @@
}
value.smallClock.view.addOnAttachStateChangeListener(
object : OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(p0: View?) {
+ var pastVisibility: Int? = null
+ override fun onViewAttachedToWindow(view: View?) {
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+ if (view != null) {
+ val smallClockFrame = view.parent as FrameLayout
+ pastVisibility = smallClockFrame.visibility
+ smallClockFrame.viewTreeObserver.addOnGlobalLayoutListener(
+ ViewTreeObserver.OnGlobalLayoutListener {
+ val currentVisibility = smallClockFrame.visibility
+ if (pastVisibility != currentVisibility) {
+ pastVisibility = currentVisibility
+ // when small clock visible, recalculate bounds and sample
+ if (currentVisibility == View.VISIBLE) {
+ smallRegionSampler?.stopRegionSampler()
+ smallRegionSampler?.startRegionSampler()
+ }
+ }
+ })
+ }
}
override fun onViewDetachedFromWindow(p0: View?) {
@@ -141,21 +180,19 @@
private fun updateColors() {
- val wallpaperManager = WallpaperManager.getInstance(context)
if (regionSamplingEnabled) {
- regionSampler?.let { regionSampler ->
- clock?.let { clock ->
- if (regionSampler.sampledView == clock.smallClock.view) {
- smallClockIsDark = regionSampler.currentRegionDarkness().isDark
- clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark)
- return@updateColors
- } else if (regionSampler.sampledView == clock.largeClock.view) {
- largeClockIsDark = regionSampler.currentRegionDarkness().isDark
- clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark)
- return@updateColors
- }
+ clock?.let { clock ->
+ smallRegionSampler?.let {
+ smallClockIsDark = it.currentRegionDarkness().isDark
+ clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark)
+ }
+
+ largeRegionSampler?.let {
+ largeClockIsDark = it.currentRegionDarkness().isDark
+ clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark)
}
}
+ return
}
val isLightTheme = TypedValue()
@@ -168,23 +205,6 @@
largeClock.events.onRegionDarknessChanged(largeClockIsDark)
}
}
-
- private fun updateRegionSampler(sampledRegion: View) {
- regionSampler?.stopRegionSampler()
- regionSampler =
- createRegionSampler(
- sampledRegion,
- mainExecutor,
- bgExecutor,
- regionSamplingEnabled,
- isLockscreen = true,
- ::updateColors
- )
- ?.apply { startRegionSampler() }
-
- updateColors()
- }
-
protected open fun createRegionSampler(
sampledView: View,
mainExecutor: Executor?,
@@ -202,7 +222,10 @@
) { updateColors() }
}
- var regionSampler: RegionSampler? = null
+ var smallRegionSampler: RegionSampler? = null
+ private set
+ var largeRegionSampler: RegionSampler? = null
+ private set
var smallTimeListener: TimeListener? = null
var largeTimeListener: TimeListener? = null
val shouldTimeListenerRun: Boolean
@@ -319,7 +342,8 @@
configurationController.removeCallback(configListener)
batteryController.removeCallback(batteryCallback)
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
- regionSampler?.stopRegionSampler()
+ smallRegionSampler?.stopRegionSampler()
+ largeRegionSampler?.stopRegionSampler()
smallTimeListener?.stop()
largeTimeListener?.stop()
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index e057188..7acfbf6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -140,6 +140,7 @@
long elapsedRealtime = SystemClock.elapsedRealtime();
long secondsInFuture = (long) Math.ceil(
(elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ getKeyguardSecurityCallback().onAttemptLockoutStart(secondsInFuture);
mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index d9d64ad..a90a34c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -255,9 +255,10 @@
if (!animate) {
out.setAlpha(0f);
out.setTranslationY(clockOutYTranslation);
+ out.setVisibility(INVISIBLE);
in.setAlpha(1f);
in.setTranslationY(clockInYTranslation);
- in.setVisibility(View.VISIBLE);
+ in.setVisibility(VISIBLE);
mStatusArea.setTranslationY(statusAreaYTranslation);
return;
}
@@ -270,7 +271,10 @@
ObjectAnimator.ofFloat(out, TRANSLATION_Y, clockOutYTranslation));
mClockOutAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mClockOutAnim = null;
+ if (mClockOutAnim == animation) {
+ out.setVisibility(INVISIBLE);
+ mClockOutAnim = null;
+ }
}
});
@@ -285,7 +289,9 @@
mClockInAnim.setStartDelay(CLOCK_IN_START_DELAY_MILLIS);
mClockInAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mClockInAnim = null;
+ if (mClockInAnim == animation) {
+ mClockInAnim = null;
+ }
}
});
@@ -299,7 +305,9 @@
ObjectAnimator.ofFloat(mSmallClockFrame, TRANSLATION_Y, statusAreaYTranslation));
mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mStatusAreaAnim = null;
+ if (mStatusAreaAnim == animation) {
+ mStatusAreaAnim = null;
+ }
}
});
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 99e2574..25ad3af 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -431,10 +431,6 @@
int clockHeight = clock.getLargeClock().getView().getHeight();
return frameHeight / 2 + clockHeight / 2 + mKeyguardLargeClockTopMargin / -2;
} else {
- // This is only called if we've never shown the large clock as the frame is inflated
- // with 'gone', but then the visibility is never set when it is animated away by
- // KeyguardClockSwitch, instead it is removed from the view hierarchy.
- // TODO(b/261755021): Cleanup Large Frame Visibility
int clockHeight = clock.getSmallClock().getView().getHeight();
return clockHeight + statusBarHeaderHeight + mKeyguardSmallClockTopMargin;
}
@@ -452,15 +448,11 @@
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
return clock.getLargeClock().getView().getHeight();
} else {
- // Is not called except in certain edge cases, see comment in getClockBottom
- // TODO(b/261755021): Cleanup Large Frame Visibility
return clock.getSmallClock().getView().getHeight();
}
}
boolean isClockTopAligned() {
- // Returns false except certain edge cases, see comment in getClockBottom
- // TODO(b/261755021): Cleanup Large Frame Visibility
return mLargeClockFrame.getVisibility() != View.VISIBLE;
}
@@ -539,9 +531,13 @@
if (clock != null) {
clock.dump(pw);
}
- final RegionSampler regionSampler = mClockEventController.getRegionSampler();
- if (regionSampler != null) {
- regionSampler.dump(pw);
+ final RegionSampler smallRegionSampler = mClockEventController.getSmallRegionSampler();
+ if (smallRegionSampler != null) {
+ smallRegionSampler.dump(pw);
+ }
+ final RegionSampler largeRegionSampler = mClockEventController.getLargeRegionSampler();
+ if (largeRegionSampler != null) {
+ largeRegionSampler.dump(pw);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 3c05299..b0a5d7c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -17,6 +17,7 @@
package com.android.keyguard;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -33,6 +34,10 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.keyguard.bouncer.ui.BouncerMessageView;
+import com.android.systemui.keyguard.ui.binder.BouncerMessageViewBinder;
+import com.android.systemui.log.BouncerLogger;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -168,6 +173,24 @@
/** Determines the message to show in the bouncer when it first appears. */
protected abstract int getInitialMessageResId();
+ /**
+ * Binds the {@link KeyguardInputView#getBouncerMessageView()} view with the provided context.
+ */
+ public void bindMessageView(
+ @NonNull BouncerMessageInteractor bouncerMessageInteractor,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ BouncerLogger bouncerLogger,
+ FeatureFlags featureFlags) {
+ BouncerMessageView bouncerMessageView = (BouncerMessageView) mView.getBouncerMessageView();
+ if (bouncerMessageView != null) {
+ BouncerMessageViewBinder.bind(bouncerMessageView,
+ bouncerMessageInteractor,
+ messageAreaControllerFactory,
+ bouncerLogger,
+ featureFlags);
+ }
+ }
+
/** Factory for a {@link KeyguardInputViewController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 64b1c50..bcf8e98 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -365,6 +365,7 @@
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long secondsInFuture = (long) Math.ceil(
(elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ getKeyguardSecurityCallback().onAttemptLockoutStart(secondsInFuture);
mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index bf9c3bb..2878df2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -87,6 +87,11 @@
default void onUserInput() {
}
+ /**
+ * Invoked when the auth input is disabled for specified number of seconds.
+ * @param seconds Number of seconds for which the auth input is disabled.
+ */
+ default void onAttemptLockoutStart(long seconds) {}
/**
* Dismisses keyguard and go to unlocked state.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b5e5420..57df33e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -74,6 +74,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -116,6 +117,7 @@
private final Optional<SideFpsController> mSideFpsController;
private final FalsingA11yDelegate mFalsingA11yDelegate;
private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+ private final BouncerMessageInteractor mBouncerMessageInteractor;
private int mTranslationY;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
@@ -178,6 +180,7 @@
@Override
public void onUserInput() {
+ mBouncerMessageInteractor.onPrimaryBouncerUserInput();
mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput();
mUpdateMonitor.cancelFaceAuth();
}
@@ -207,7 +210,15 @@
}
@Override
+ public void onAttemptLockoutStart(long seconds) {
+ mBouncerMessageInteractor.onPrimaryAuthLockedOut(seconds);
+ }
+
+ @Override
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
+ if (timeoutMs == 0 && !success) {
+ mBouncerMessageInteractor.onPrimaryAuthIncorrectAttempt();
+ }
int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
if (mView.isSidedSecurityMode()) {
bouncerSide = mView.isSecurityLeftAligned()
@@ -392,7 +403,8 @@
TelephonyManager telephonyManager,
ViewMediatorCallback viewMediatorCallback,
AudioManager audioManager,
- KeyguardFaceAuthInteractor keyguardFaceAuthInteractor
+ KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
+ BouncerMessageInteractor bouncerMessageInteractor
) {
super(view);
mLockPatternUtils = lockPatternUtils;
@@ -418,6 +430,7 @@
mViewMediatorCallback = viewMediatorCallback;
mAudioManager = audioManager;
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
+ mBouncerMessageInteractor = bouncerMessageInteractor;
}
@Override
@@ -438,6 +451,7 @@
// Update ViewMediator with the current input method requirements
mViewMediatorCallback.setNeedsInput(needsInput());
mView.setOnKeyListener(mOnKeyListener);
+
showPrimarySecurityScreen(false);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1721891..894158c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1462,14 +1462,6 @@
ErrorAuthenticationStatus error = (ErrorAuthenticationStatus) status;
handleFaceError(error.getMsgId(), error.getMsg());
} else if (status instanceof FailedAuthenticationStatus) {
- if (isFaceLockedOut()) {
- // TODO b/270090188: remove this hack when biometrics fixes this issue.
- // FailedAuthenticationStatus is emitted after ErrorAuthenticationStatus
- // for lockout error is received
- mLogger.d("onAuthenticationFailed called after"
- + " face has been locked out");
- return;
- }
handleFaceAuthFailed();
} else if (status instanceof HelpAuthenticationStatus) {
HelpAuthenticationStatus helpMsg = (HelpAuthenticationStatus) status;
@@ -1980,13 +1972,6 @@
@Override
public void onAuthenticationFailed() {
- if (isFaceLockedOut()) {
- // TODO b/270090188: remove this hack when biometrics fixes this issue.
- // onAuthenticationFailed is called after onAuthenticationError
- // for lockout error is received
- mLogger.d("onAuthenticationFailed called after face has been locked out");
- return;
- }
handleFaceAuthFailed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index c3bb423..fd3c158 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -87,14 +87,15 @@
}
/**
- * Shows magnification settings panel {@link WindowMagnificationSettings}.
+ * Toggles the visibility of magnification settings panel {@link WindowMagnificationSettings}.
+ * We show the panel if it is not visible. Otherwise, hide the panel.
*/
- void showMagnificationSettings() {
+ void toggleSettingsPanelVisibility() {
if (!mWindowMagnificationSettings.isSettingPanelShowing()) {
onConfigurationChanged(mContext.getResources().getConfiguration());
mContext.registerComponentCallbacks(this);
}
- mWindowMagnificationSettings.showSettingPanel();
+ mWindowMagnificationSettings.toggleSettingsPanelVisibility();
}
void closeMagnificationSettings() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index e2b85fa..2a14dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -171,7 +171,7 @@
mModeSwitchesController.setClickListenerDelegate(
displayId -> mHandler.post(() -> {
- showMagnificationSettingsPanel(displayId);
+ toggleSettingsPanelVisibility(displayId);
}));
}
@@ -254,11 +254,11 @@
}
@MainThread
- void showMagnificationSettingsPanel(int displayId) {
+ void toggleSettingsPanelVisibility(int displayId) {
final MagnificationSettingsController magnificationSettingsController =
mMagnificationSettingsSupplier.get(displayId);
if (magnificationSettingsController != null) {
- magnificationSettingsController.showMagnificationSettings();
+ magnificationSettingsController.toggleSettingsPanelVisibility();
}
}
@@ -335,7 +335,7 @@
@Override
public void onClickSettingsButton(int displayId) {
mHandler.post(() -> {
- showMagnificationSettingsPanel(displayId);
+ toggleSettingsPanelVisibility(displayId);
});
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index a67f706..7c76588 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -221,6 +221,7 @@
private boolean mAllowDiagonalScrolling = false;
private boolean mEditSizeEnable = false;
+ private boolean mSettingsPanelVisibility = false;
@Nullable
private final MirrorWindowControl mMirrorWindowControl;
@@ -1399,6 +1400,8 @@
return;
}
+ mSettingsPanelVisibility = settingsPanelIsShown;
+
mDragView.setBackground(mContext.getResources().getDrawable(settingsPanelIsShown
? R.drawable.accessibility_window_magnification_drag_handle_background_change
: R.drawable.accessibility_window_magnification_drag_handle_background));
@@ -1439,12 +1442,19 @@
private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {
+ private CharSequence getClickAccessibilityActionLabel() {
+ return mSettingsPanelVisibility
+ ? mContext.getResources().getString(
+ R.string.magnification_close_settings_click_label)
+ : mContext.getResources().getString(
+ R.string.magnification_open_settings_click_label);
+ }
+
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
final AccessibilityAction clickAction = new AccessibilityAction(
- AccessibilityAction.ACTION_CLICK.getId(), mContext.getResources().getString(
- R.string.magnification_open_settings_click_label));
+ AccessibilityAction.ACTION_CLICK.getId(), getClickAccessibilityActionLabel());
info.addAction(clickAction);
info.setClickable(true);
info.addAction(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 3b1d695..d27087d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -79,7 +79,8 @@
private final Runnable mWindowInsetChangeRunnable;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- private final LayoutParams mParams;
+ @VisibleForTesting
+ final LayoutParams mParams;
@VisibleForTesting
final Rect mDraggableWindowBounds = new Rect();
private boolean mIsVisible = false;
@@ -311,6 +312,14 @@
mCallback.onSettingsPanelVisibilityChanged(/* shown= */ false);
}
+ public void toggleSettingsPanelVisibility() {
+ if (!mIsVisible) {
+ showSettingPanel();
+ } else {
+ hideSettingPanel();
+ }
+ }
+
public void showSettingPanel() {
showSettingPanel(true);
}
@@ -521,7 +530,6 @@
// CONFIG_FONT_SCALE: font size change
// CONFIG_LOCALE: language change
// CONFIG_DENSITY: display size change
-
mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
boolean showSettingPanelAfterConfigChange = mIsVisible;
@@ -533,16 +541,13 @@
return;
}
- if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
- final Rect previousDraggableBounds = new Rect(mDraggableWindowBounds);
+ if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0
+ || (configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
mDraggableWindowBounds.set(getDraggableWindowBounds());
- // Keep the Y position with the same height ratio before the window bounds and
- // draggable bounds are changed.
- final float windowHeightFraction = (float) (mParams.y - previousDraggableBounds.top)
- / previousDraggableBounds.height();
- mParams.y = (int) (windowHeightFraction * mDraggableWindowBounds.height())
- + mDraggableWindowBounds.top;
- return;
+ // reset the panel position to the right-bottom corner
+ mParams.x = mDraggableWindowBounds.right;
+ mParams.y = mDraggableWindowBounds.bottom;
+ updateButtonViewLayoutIfNeeded();
}
}
@@ -554,7 +559,8 @@
mDraggableWindowBounds.set(newBounds);
}
- private void updateButtonViewLayoutIfNeeded() {
+ @VisibleForTesting
+ void updateButtonViewLayoutIfNeeded() {
if (mIsVisible) {
mParams.x = MathUtils.constrain(mParams.x, mDraggableWindowBounds.left,
mDraggableWindowBounds.right);
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index c684dc5..c4ebee2 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -77,7 +77,7 @@
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
private val _authenticationMethod =
- MutableStateFlow<AuthenticationMethodModel>(AuthenticationMethodModel.PIN(1234))
+ MutableStateFlow<AuthenticationMethodModel>(AuthenticationMethodModel.Pin(1234))
override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
_authenticationMethod.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 3984627..dd9dcbe 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.authentication.domain.interactor
+import android.app.admin.DevicePolicyManager
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.dagger.SysUISingleton
@@ -129,7 +130,7 @@
fun authenticate(input: List<Any>): Boolean {
val isSuccessful =
when (val authMethod = this.authenticationMethod.value) {
- is AuthenticationMethodModel.PIN -> input.asCode() == authMethod.code
+ is AuthenticationMethodModel.Pin -> input.asCode() == authMethod.code
is AuthenticationMethodModel.Password -> input.asPassword() == authMethod.password
is AuthenticationMethodModel.Pattern -> input.asPattern() == authMethod.coordinates
else -> true
@@ -177,15 +178,21 @@
/**
* Returns a PIN code from the given list. It's assumed the given list elements are all
- * [Int].
+ * [Int] in the range [0-9].
*/
- private fun List<Any>.asCode(): Int? {
- if (isEmpty()) {
+ private fun List<Any>.asCode(): Long? {
+ if (isEmpty() || size > DevicePolicyManager.MAX_PASSWORD_LENGTH) {
return null
}
- var code = 0
- map { it as Int }.forEach { integer -> code = code * 10 + integer }
+ var code = 0L
+ map {
+ require(it is Int && it in 0..9) {
+ "Pin is required to be Int in range [0..9], but got $it"
+ }
+ it
+ }
+ .forEach { integer -> code = code * 10 + integer }
return code
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
index 6f008c3..e4fbf9a 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
@@ -32,7 +32,13 @@
/** The most basic authentication method. The lock screen can be swiped away when displayed. */
object Swipe : AuthenticationMethodModel(isSecure = false)
- data class PIN(val code: Int) : AuthenticationMethodModel(isSecure = true)
+ /**
+ * Authentication method using a PIN.
+ *
+ * In practice, a pin is restricted to 16 decimal digits , see
+ * [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH]
+ */
+ data class Pin(val code: Long) : AuthenticationMethodModel(isSecure = true)
data class Password(val password: String) : AuthenticationMethodModel(isSecure = true)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 1d2fce7..a24a421 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -197,7 +197,7 @@
private fun promptMessage(authMethod: AuthenticationMethodModel): String {
return when (authMethod) {
- is AuthenticationMethodModel.PIN ->
+ is AuthenticationMethodModel.Pin ->
applicationContext.getString(R.string.keyguard_enter_your_pin)
is AuthenticationMethodModel.Password ->
applicationContext.getString(R.string.keyguard_enter_your_password)
@@ -209,7 +209,7 @@
private fun errorMessage(authMethod: AuthenticationMethodModel): String {
return when (authMethod) {
- is AuthenticationMethodModel.PIN -> applicationContext.getString(R.string.kg_wrong_pin)
+ is AuthenticationMethodModel.Pin -> applicationContext.getString(R.string.kg_wrong_pin)
is AuthenticationMethodModel.Password ->
applicationContext.getString(R.string.kg_wrong_password)
is AuthenticationMethodModel.Pattern ->
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 984d9ab..527fe6e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -126,7 +126,7 @@
.map { model ->
model?.let {
when (interactor.authenticationMethod.value) {
- is AuthenticationMethodModel.PIN ->
+ is AuthenticationMethodModel.Pin ->
R.string.kg_too_many_failed_pin_attempts_dialog_message
is AuthenticationMethodModel.Password ->
R.string.kg_too_many_failed_password_attempts_dialog_message
@@ -165,7 +165,7 @@
authMethod: AuthenticationMethodModel,
): AuthMethodBouncerViewModel? {
return when (authMethod) {
- is AuthenticationMethodModel.PIN -> pin
+ is AuthenticationMethodModel.Pin -> pin
is AuthenticationMethodModel.Password -> password
is AuthenticationMethodModel.Pattern -> pattern
else -> null
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 5c0fd92..94d3d19 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -16,18 +16,10 @@
package com.android.systemui.bouncer.ui.viewmodel
-import androidx.annotation.VisibleForTesting
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
-import com.android.systemui.util.kotlin.pairwise
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
@@ -39,21 +31,8 @@
isInputEnabled = isInputEnabled,
) {
- private val entered = MutableStateFlow<List<Int>>(emptyList())
- /**
- * The length of the PIN digits that were input so far, two values are supplied the previous and
- * the current.
- */
- val pinLengths: StateFlow<Pair<Int, Int>> =
- entered
- .pairwise()
- .map { it.previousValue.size to it.newValue.size }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = 0 to 0,
- )
- private var resetPinJob: Job? = null
+ private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
+ val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
/** Notifies that the UI has been shown to the user. */
fun onShown() {
@@ -62,47 +41,48 @@
/** Notifies that the user clicked on a PIN button with the given digit value. */
fun onPinButtonClicked(input: Int) {
- resetPinJob?.cancel()
- resetPinJob = null
-
- if (entered.value.isEmpty()) {
+ if (mutablePinEntries.value.isEmpty()) {
interactor.clearMessage()
}
- entered.value += input
+ mutablePinEntries.value += EnteredKey(input)
}
/** Notifies that the user clicked the backspace button. */
fun onBackspaceButtonClicked() {
- if (entered.value.isEmpty()) {
+ if (mutablePinEntries.value.isEmpty()) {
return
}
-
- entered.value = entered.value.toMutableList().apply { removeLast() }
+ mutablePinEntries.value = mutablePinEntries.value.toMutableList().apply { removeLast() }
}
/** Notifies that the user long-pressed the backspace button. */
fun onBackspaceButtonLongPressed() {
- resetPinJob?.cancel()
- resetPinJob =
- applicationScope.launch {
- while (entered.value.isNotEmpty()) {
- onBackspaceButtonClicked()
- delay(BACKSPACE_LONG_PRESS_DELAY_MS)
- }
- }
+ mutablePinEntries.value = emptyList()
}
/** Notifies that the user clicked the "enter" button. */
fun onAuthenticateButtonClicked() {
- if (!interactor.authenticate(entered.value)) {
+ if (!interactor.authenticate(mutablePinEntries.value.map { it.input })) {
showFailureAnimation()
}
- entered.value = emptyList()
+ mutablePinEntries.value = emptyList()
}
+}
- companion object {
- @VisibleForTesting const val BACKSPACE_LONG_PRESS_DELAY_MS = 80L
- }
+private var nextSequenceNumber = 1
+
+/**
+ * The pin bouncer [input] as digits 0-9, together with a [sequenceNumber] to indicate the ordering.
+ *
+ * Since the model only allows appending/removing [EnteredKey]s from the end, the [sequenceNumber]
+ * is strictly increasing in input order of the pin, but not guaranteed to be monotonic or start at
+ * a specific number.
+ */
+data class EnteredKey
+internal constructor(val input: Int, val sequenceNumber: Int = nextSequenceNumber++) :
+ Comparable<EnteredKey> {
+ override fun compareTo(other: EnteredKey): Int =
+ compareValuesBy(this, other, EnteredKey::sequenceNumber)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 25634f0..76002d3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.KeyguardViewConfigurator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
import com.android.systemui.log.SessionTracker
import com.android.systemui.media.RingtonePlayer
@@ -295,4 +296,9 @@
@IntoMap
@ClassKey(AssistantAttentionMonitor::class)
abstract fun bindAssistantAttentionMonitor(sysui: AssistantAttentionMonitor): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardViewConfigurator::class)
+ abstract fun bindKeyguardViewConfigurator(impl: KeyguardViewConfigurator): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b52b59e..432ec8a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -72,10 +72,6 @@
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
unreleasedFlag(119, "notification_memory_logging_enabled")
- @JvmField
- val SIMPLIFIED_APPEAR_FRACTION =
- releasedFlag(259395680, "simplified_appear_fraction")
-
// TODO(b/257315550): Tracking Bug
val NO_HUN_FOR_OLD_WHEN = releasedFlag(118, "no_hun_for_old_when")
@@ -359,7 +355,8 @@
// TODO(b/280426085): Tracking Bug
@JvmField
- val NEW_BLUETOOTH_REPOSITORY = unreleasedFlag(612, "new_bluetooth_repository")
+ val NEW_BLUETOOTH_REPOSITORY =
+ unreleasedFlag(612, "new_bluetooth_repository", teamfood = true)
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
@@ -573,7 +570,7 @@
// TODO(b/270987164): Tracking Bug
@JvmField
- val TRACKPAD_GESTURE_FEATURES = unreleasedFlag(1205, "trackpad_gesture_features", teamfood = true)
+ val TRACKPAD_GESTURE_FEATURES = releasedFlag(1205, "trackpad_gesture_features")
// TODO(b/263826204): Tracking Bug
@JvmField
@@ -632,6 +629,9 @@
// TODO(b/265944639): Tracking Bug
@JvmField val DUAL_SHADE = unreleasedFlag(1801, "dual_shade")
+ // TODO(b/283300105): Tracking Bug
+ @JvmField val SCENE_CONTAINER = unreleasedFlag(1802, "scene_container")
+
// 1900
@JvmField val NOTE_TASKS = releasedFlag(1900, "keycode_flag")
@@ -706,8 +706,7 @@
// TODO(b/259428678): Tracking Bug
@JvmField
- val KEYBOARD_BACKLIGHT_INDICATOR =
- unreleasedFlag(2601, "keyboard_backlight_indicator", teamfood = true)
+ val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag(2601, "keyboard_backlight_indicator")
// TODO(b/277192623): Tracking Bug
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
index 757afb6..67c85bd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
@@ -16,11 +16,19 @@
package com.android.systemui.keyguard;
+import android.annotation.IntDef;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
-import android.os.Trace;
+import android.os.TraceNameSupplier;
+
+import androidx.annotation.NonNull;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import javax.inject.Inject;
@@ -29,7 +37,6 @@
*/
@SysUISingleton
public class KeyguardLifecyclesDispatcher {
-
static final int SCREEN_TURNING_ON = 0;
static final int SCREEN_TURNED_ON = 1;
static final int SCREEN_TURNING_OFF = 2;
@@ -39,19 +46,46 @@
static final int FINISHED_WAKING_UP = 5;
static final int STARTED_GOING_TO_SLEEP = 6;
static final int FINISHED_GOING_TO_SLEEP = 7;
- private static final String TAG = "KeyguardLifecyclesDispatcher";
- private final ScreenLifecycle mScreenLifecycle;
- private final WakefulnessLifecycle mWakefulnessLifecycle;
-
- @Inject
- public KeyguardLifecyclesDispatcher(ScreenLifecycle screenLifecycle,
- WakefulnessLifecycle wakefulnessLifecycle) {
- mScreenLifecycle = screenLifecycle;
- mWakefulnessLifecycle = wakefulnessLifecycle;
+ @IntDef({
+ SCREEN_TURNING_ON,
+ SCREEN_TURNED_ON,
+ SCREEN_TURNING_OFF,
+ SCREEN_TURNED_OFF,
+ STARTED_WAKING_UP,
+ FINISHED_WAKING_UP,
+ STARTED_GOING_TO_SLEEP,
+ FINISHED_GOING_TO_SLEEP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KeyguardLifecycleMessageType {
}
- void dispatch(int what) {
+ private static String getNameOfMessage(@KeyguardLifecycleMessageType int what) {
+ return switch (what) {
+ case SCREEN_TURNING_ON -> "SCREEN_TURNING_ON";
+ case SCREEN_TURNED_ON -> "SCREEN_TURNED_ON";
+ case SCREEN_TURNING_OFF -> "SCREEN_TURNING_OFF";
+ case SCREEN_TURNED_OFF -> "SCREEN_TURNED_OFF";
+ case STARTED_WAKING_UP -> "STARTED_WAKING_UP";
+ case FINISHED_WAKING_UP -> "FINISHED_WAKING_UP";
+ case STARTED_GOING_TO_SLEEP -> "STARTED_GOING_TO_SLEEP";
+ case FINISHED_GOING_TO_SLEEP -> "FINISHED_GOING_TO_SLEEP";
+ default -> "UNKNOWN";
+ };
+ }
+
+ private final Handler mHandler;
+
+ @Inject
+ public KeyguardLifecyclesDispatcher(
+ @Main Looper mainLooper,
+ ScreenLifecycle screenLifecycle,
+ WakefulnessLifecycle wakefulnessLifecycle) {
+ mHandler = new KeyguardLifecycleHandler(mainLooper, screenLifecycle, wakefulnessLifecycle);
+ }
+
+ void dispatch(@KeyguardLifecycleMessageType int what) {
mHandler.obtainMessage(what).sendToTarget();
}
@@ -60,7 +94,7 @@
* @param pmReason Reason this message was triggered - this should be a value from either
* {@link PowerManager.WakeReason} or {@link PowerManager.GoToSleepReason}.
*/
- void dispatch(int what, int pmReason) {
+ void dispatch(@KeyguardLifecycleMessageType int what, int pmReason) {
final Message message = mHandler.obtainMessage(what);
message.arg1 = pmReason;
message.sendToTarget();
@@ -70,44 +104,48 @@
* @param what Message to send.
* @param object Object to send with the message
*/
- void dispatch(int what, Object object) {
+ void dispatch(@KeyguardLifecycleMessageType int what, Object object) {
mHandler.obtainMessage(what, object).sendToTarget();
}
- private Handler mHandler = new Handler() {
+ private static class KeyguardLifecycleHandler extends Handler {
+ private static final String TAG = "KeyguardLifecycleHandler";
+ private final ScreenLifecycle mScreenLifecycle;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
+
+ public KeyguardLifecycleHandler(Looper looper,
+ ScreenLifecycle screenLifecycle,
+ WakefulnessLifecycle wakefulnessLifecycle) {
+ super(looper);
+ mScreenLifecycle = screenLifecycle;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
+ }
+
+ @NonNull
@Override
- public void handleMessage(Message msg) {
+ public String getTraceName(@NonNull Message msg) {
+ if (msg.getCallback() instanceof TraceNameSupplier || msg.getCallback() != null) {
+ return super.getTraceName(msg);
+ }
+ return TAG + "#" + getNameOfMessage(msg.what);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
- case SCREEN_TURNING_ON:
- Trace.beginSection("KeyguardLifecyclesDispatcher#SCREEN_TURNING_ON");
- mScreenLifecycle.dispatchScreenTurningOn();
- Trace.endSection();
- break;
- case SCREEN_TURNED_ON:
- mScreenLifecycle.dispatchScreenTurnedOn();
- break;
- case SCREEN_TURNING_OFF:
- mScreenLifecycle.dispatchScreenTurningOff();
- break;
- case SCREEN_TURNED_OFF:
- mScreenLifecycle.dispatchScreenTurnedOff();
- break;
- case STARTED_WAKING_UP:
- mWakefulnessLifecycle.dispatchStartedWakingUp(msg.arg1 /* pmReason */);
- break;
- case FINISHED_WAKING_UP:
- mWakefulnessLifecycle.dispatchFinishedWakingUp();
- break;
- case STARTED_GOING_TO_SLEEP:
- mWakefulnessLifecycle.dispatchStartedGoingToSleep(msg.arg1 /* pmReason */);
- break;
- case FINISHED_GOING_TO_SLEEP:
- mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
- break;
- default:
- throw new IllegalArgumentException("Unknown message: " + msg);
+ case SCREEN_TURNING_ON -> mScreenLifecycle.dispatchScreenTurningOn();
+ case SCREEN_TURNED_ON -> mScreenLifecycle.dispatchScreenTurnedOn();
+ case SCREEN_TURNING_OFF -> mScreenLifecycle.dispatchScreenTurningOff();
+ case SCREEN_TURNED_OFF -> mScreenLifecycle.dispatchScreenTurnedOff();
+ case STARTED_WAKING_UP ->
+ mWakefulnessLifecycle.dispatchStartedWakingUp(msg.arg1 /* pmReason */);
+ case FINISHED_WAKING_UP -> mWakefulnessLifecycle.dispatchFinishedWakingUp();
+ case STARTED_GOING_TO_SLEEP ->
+ mWakefulnessLifecycle.dispatchStartedGoingToSleep(msg.arg1 /* pmReason */);
+ case FINISHED_GOING_TO_SLEEP ->
+ mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
+ default -> throw new IllegalArgumentException("Unknown message: " + msg);
}
}
- };
-
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
new file mode 100644
index 0000000..05c23ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.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.keyguard
+
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.CoreStartable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
+import com.android.systemui.shade.NotificationShadeWindowView
+import com.android.systemui.statusbar.KeyguardIndicationController
+import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
+
+/** Binds keyguard views on startup, and also exposes methods to allow rebinding if views change */
+@SysUISingleton
+class KeyguardViewConfigurator
+@Inject
+constructor(
+ private val keyguardRootView: KeyguardRootView,
+ private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel,
+ private val notificationShadeWindowView: NotificationShadeWindowView,
+ private val featureFlags: FeatureFlags,
+ private val indicationController: KeyguardIndicationController,
+) : CoreStartable {
+
+ private var indicationAreaHandle: DisposableHandle? = null
+
+ override fun start() {
+ bindIndicationArea(
+ notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup
+ )
+ }
+
+ fun bindIndicationArea(legacyParent: ViewGroup) {
+ indicationAreaHandle?.dispose()
+
+ // At startup, 2 views with the ID `R.id.keyguard_indication_area` will be available.
+ // Disable one of them
+ if (featureFlags.isEnabled(Flags.MIGRATE_INDICATION_AREA)) {
+ legacyParent.requireViewById<View>(R.id.keyguard_indication_area).let {
+ legacyParent.removeView(it)
+ }
+ } else {
+ keyguardRootView.findViewById<View?>(R.id.keyguard_indication_area)?.let {
+ keyguardRootView.removeView(it)
+ }
+ }
+
+ indicationAreaHandle =
+ KeyguardIndicationAreaBinder.bind(
+ notificationShadeWindowView,
+ keyguardIndicationAreaViewModel,
+ indicationController
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b40d86..81f325f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
+import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
+import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
@@ -70,7 +72,6 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -93,7 +94,6 @@
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
-import android.window.IRemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -154,6 +154,9 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.SystemSettings;
+import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.keyguard.KeyguardTransitions;
import dagger.Lazy;
@@ -161,7 +164,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Optional;
import java.util.concurrent.Executor;
/**
@@ -215,7 +217,7 @@
private final static String TAG = "KeyguardViewMediator";
- private static final String DELAYED_KEYGUARD_ACTION =
+ public static final String DELAYED_KEYGUARD_ACTION =
"com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
private static final String DELAYED_LOCK_PROFILE_ACTION =
"com.android.internal.policy.impl.PhoneWindowManager.DELAYED_LOCK";
@@ -250,7 +252,7 @@
* turning on the keyguard (i.e, the user has this much time to turn
* the screen back on without having to face the keyguard).
*/
- private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000;
+ public static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000;
/**
* How long we'll wait for the {@link ViewMediatorCallback#keyguardDoneDrawing()}
@@ -306,6 +308,9 @@
/** UserSwitcherController for creating guest user on boot complete */
private final UserSwitcherController mUserSwitcherController;
+ private final SecureSettings mSecureSettings;
+ private final SystemSettings mSystemSettings;
+ private final SystemClock mSystemClock;
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -1253,7 +1258,10 @@
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ SecureSettings secureSettings,
+ SystemSettings systemSettings,
+ SystemClock systemClock) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1267,6 +1275,9 @@
mPM = powerManager;
mTrustManager = trustManager;
mUserSwitcherController = userSwitcherController;
+ mSecureSettings = secureSettings;
+ mSystemSettings = systemSettings;
+ mSystemClock = systemClock;
mStatusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mKeyguardDisplayManager = keyguardDisplayManager;
@@ -1316,7 +1327,7 @@
}
public void userActivity() {
- mPM.userActivity(SystemClock.uptimeMillis(), false);
+ mPM.userActivity(mSystemClock.uptimeMillis(), false);
}
private void setupLocked() {
@@ -1502,7 +1513,7 @@
if (cameraGestureTriggered) {
// Just to make sure, make sure the device is awake.
- mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
+ mContext.getSystemService(PowerManager.class).wakeUp(mSystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_CAMERA_LAUNCH,
"com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
setPendingLock(false);
@@ -1599,12 +1610,11 @@
// to enable it a bit later (i.e, give the user a chance
// to turn the screen back on within a certain window without
// having to unlock the screen)
- final ContentResolver cr = mContext.getContentResolver();
// From SecuritySettings
- final long lockAfterTimeout = Settings.Secure.getIntForUser(cr,
- Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
- KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, userId);
+ final long lockAfterTimeout = mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT,
+ userId);
// From DevicePolicyAdmin
final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
@@ -1616,8 +1626,9 @@
timeout = lockAfterTimeout;
} else {
// From DisplaySettings
- long displayTimeout = Settings.System.getIntForUser(cr, SCREEN_OFF_TIMEOUT,
- KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT, userId);
+ long displayTimeout = mSystemSettings.getIntForUser(SCREEN_OFF_TIMEOUT,
+ KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT,
+ userId);
// policy in effect. Make sure we don't go beyond policy limit.
displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
@@ -1638,7 +1649,7 @@
private void doKeyguardLaterLocked(long timeout) {
// Lock in the future
- long when = SystemClock.elapsedRealtime() + timeout;
+ long when = mSystemClock.elapsedRealtime() + timeout;
Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
intent.setPackage(mContext.getPackageName());
intent.putExtra("seq", mDelayedShowingSequence);
@@ -1660,7 +1671,7 @@
if (userTimeout == 0) {
doKeyguardForChildProfilesLocked();
} else {
- long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+ long userWhen = mSystemClock.elapsedRealtime() + userTimeout;
Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
lockIntent.setPackage(mContext.getPackageName());
lockIntent.putExtra("seq", mDelayedProfileShowingSequence);
@@ -2468,9 +2479,7 @@
private void playSound(int soundId) {
if (soundId == 0) return;
- final ContentResolver cr = mContext.getContentResolver();
- int lockscreenSoundsEnabled = Settings.System.getIntForUser(cr,
- Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1,
+ int lockscreenSoundsEnabled = mSystemSettings.getIntForUser(LOCKSCREEN_SOUNDS_ENABLED, 1,
KeyguardUpdateMonitor.getCurrentUser());
if (lockscreenSoundsEnabled == 1) {
@@ -2647,7 +2656,7 @@
// It's possible that the device was unlocked (via BOUNCER) while dozing. It's time to
// wake up.
if (mAodShowing) {
- mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ mPM.wakeUp(mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:BOUNCER_DOZING");
}
@@ -2662,7 +2671,7 @@
// TODO(bc-unlock): Fill parameters
mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(() -> {
handleStartKeyguardExitAnimation(
- SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
+ mSystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */,
null /* nonApps */, null /* finishedCallback */);
});
@@ -2671,7 +2680,7 @@
// It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
// dreaming. It's time to wake up.
if (mDreamOverlayShowing) {
- mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ mPM.wakeUp(mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:UNLOCK_DREAMING");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7c039d..1c5bb5f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -64,6 +64,9 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.SystemSettings;
+import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.keyguard.KeyguardTransitions;
import dagger.Lazy;
@@ -128,7 +131,10 @@
Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ SecureSettings secureSettings,
+ SystemSettings systemSettings,
+ SystemClock systemClock) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -162,7 +168,10 @@
notificationShadeWindowController,
activityLaunchAnimator,
scrimControllerLazy,
- featureFlags);
+ featureFlags,
+ secureSettings,
+ systemSettings,
+ systemClock);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 3cf9a9e..f99b8a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -21,6 +21,7 @@
import android.graphics.Point
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -59,6 +60,7 @@
private val commandQueue: CommandQueue,
featureFlags: FeatureFlags,
bouncerRepository: KeyguardBouncerRepository,
+ configurationRepository: ConfigurationRepository,
) {
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -172,6 +174,9 @@
/** The approximate location on the screen of the face unlock sensor, if one is available. */
val faceSensorLocation: Flow<Point?> = repository.faceSensorLocation
+ /** Notifies when a new configuration is set */
+ val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange
+
fun dozeTransitionTo(vararg states: DozeStateModel): Flow<DozeTransitionModel> {
return dozeTransitionModel.filter { states.contains(it.to) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt
new file mode 100644
index 0000000..5b40dd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import android.text.TextUtils
+import android.util.PluralsMessageFormatter
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.keyguard.BouncerKeyguardMessageArea
+import com.android.keyguard.KeyguardMessageArea
+import com.android.keyguard.KeyguardMessageAreaController
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.keyguard.bouncer.shared.model.Message
+import com.android.systemui.keyguard.bouncer.ui.BouncerMessageView
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.log.BouncerLogger
+import kotlinx.coroutines.launch
+
+object BouncerMessageViewBinder {
+ @JvmStatic
+ fun bind(
+ view: BouncerMessageView,
+ interactor: BouncerMessageInteractor,
+ factory: KeyguardMessageAreaController.Factory,
+ bouncerLogger: BouncerLogger,
+ featureFlags: FeatureFlags
+ ) {
+ view.repeatWhenAttached {
+ if (!featureFlags.isEnabled(Flags.REVAMPED_BOUNCER_MESSAGES)) {
+ view.primaryMessageView?.disable()
+ view.secondaryMessageView?.disable()
+ return@repeatWhenAttached
+ }
+ view.init(factory)
+ view.primaryMessage?.setIsVisible(true)
+ view.secondaryMessage?.setIsVisible(true)
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ bouncerLogger.startBouncerMessageInteractor()
+ launch {
+ interactor.bouncerMessage.collect {
+ bouncerLogger.bouncerMessageUpdated(it)
+ updateView(
+ view.primaryMessage,
+ view.primaryMessageView,
+ message = it?.message,
+ allowTruncation = true,
+ )
+ updateView(
+ view.secondaryMessage,
+ view.secondaryMessageView,
+ message = it?.secondaryMessage,
+ allowTruncation = false,
+ )
+ view.requestLayout()
+ }
+ }
+ }
+ }
+ }
+
+ private fun updateView(
+ controller: KeyguardMessageAreaController<KeyguardMessageArea>?,
+ view: BouncerKeyguardMessageArea?,
+ message: Message?,
+ allowTruncation: Boolean = false,
+ ) {
+ if (view == null || controller == null) return
+ if (message?.message != null || message?.messageResId != null) {
+ controller.setIsVisible(true)
+ var newMessage = message.message ?: ""
+ if (message.messageResId != null && message.messageResId != 0) {
+ newMessage = view.resources.getString(message.messageResId)
+ if (message.formatterArgs != null) {
+ newMessage =
+ PluralsMessageFormatter.format(
+ view.resources,
+ message.formatterArgs,
+ message.messageResId
+ )
+ }
+ }
+ controller.setMessage(newMessage, message.animate)
+ } else {
+ controller.setIsVisible(false)
+ controller.setMessage(0)
+ }
+ message?.colorState?.let { controller.setNextMessageColor(it) }
+ view.ellipsize =
+ if (allowTruncation) TextUtils.TruncateAt.END else TextUtils.TruncateAt.MARQUEE
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index a8d662c..7d14198 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -21,12 +21,10 @@
import android.graphics.Rect
import android.graphics.drawable.Animatable2
import android.util.Size
-import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.view.ViewPropertyAnimator
import android.widget.ImageView
-import android.widget.TextView
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
@@ -108,14 +106,10 @@
activityStarter: ActivityStarter?,
messageDisplayer: (Int) -> Unit,
): Binding {
- val indicationArea: View = view.requireViewById(R.id.keyguard_indication_area)
val ambientIndicationArea: View? = view.findViewById(R.id.ambient_indication_container)
val startButton: ImageView = view.requireViewById(R.id.start_button)
val endButton: ImageView = view.requireViewById(R.id.end_button)
val overlayContainer: View = view.requireViewById(R.id.overlay_container)
- val indicationText: TextView = view.requireViewById(R.id.keyguard_indication_text)
- val indicationTextBottom: TextView =
- view.requireViewById(R.id.keyguard_indication_text_bottom)
val settingsMenu: LaunchableLinearLayout =
view.requireViewById(R.id.keyguard_settings_button)
@@ -183,7 +177,6 @@
}
ambientIndicationArea?.alpha = alpha
- indicationArea.alpha = alpha
}
}
@@ -205,50 +198,23 @@
launch {
viewModel.indicationAreaTranslationX.collect { translationX ->
- indicationArea.translationX = translationX
ambientIndicationArea?.translationX = translationX
}
}
launch {
- combine(
- viewModel.isIndicationAreaPadded,
- configurationBasedDimensions.map { it.indicationAreaPaddingPx },
- ) { isPadded, paddingIfPaddedPx ->
- if (isPadded) {
- paddingIfPaddedPx
- } else {
- 0
- }
- }
- .collect { paddingPx ->
- indicationArea.setPadding(paddingPx, 0, paddingPx, 0)
- }
- }
-
- launch {
configurationBasedDimensions
.map { it.defaultBurnInPreventionYOffsetPx }
.flatMapLatest { defaultBurnInOffsetY ->
viewModel.indicationAreaTranslationY(defaultBurnInOffsetY)
}
.collect { translationY ->
- indicationArea.translationY = translationY
ambientIndicationArea?.translationY = translationY
}
}
launch {
configurationBasedDimensions.collect { dimensions ->
- indicationText.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- dimensions.indicationTextSizePx.toFloat(),
- )
- indicationTextBottom.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- dimensions.indicationTextSizePx.toFloat(),
- )
-
startButton.updateLayoutParams<ViewGroup.LayoutParams> {
width = dimensions.buttonSizePx.width
height = dimensions.buttonSizePx.height
@@ -305,7 +271,7 @@
return object : Binding {
override fun getIndicationAreaAnimators(): List<ViewPropertyAnimator> {
- return listOf(indicationArea, ambientIndicationArea).mapNotNull { it?.animate() }
+ return listOf(ambientIndicationArea).mapNotNull { it?.animate() }
}
override fun onConfigurationChanged() {
@@ -517,12 +483,6 @@
return ConfigurationBasedDimensions(
defaultBurnInPreventionYOffsetPx =
view.resources.getDimensionPixelOffset(R.dimen.default_burn_in_prevention_offset),
- indicationAreaPaddingPx =
- view.resources.getDimensionPixelOffset(R.dimen.keyguard_indication_area_padding),
- indicationTextSizePx =
- view.resources.getDimensionPixelSize(
- com.android.internal.R.dimen.text_size_small_material,
- ),
buttonSizePx =
Size(
view.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width),
@@ -552,8 +512,6 @@
private data class ConfigurationBasedDimensions(
val defaultBurnInPreventionYOffsetPx: Int,
- val indicationAreaPaddingPx: Int,
- val indicationTextSizePx: Int,
val buttonSizePx: Size,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index c1aefc7..dd1a9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -22,16 +22,20 @@
import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.log.BouncerLogger
import com.android.systemui.plugins.ActivityStarter
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.filter
@@ -44,7 +48,11 @@
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
- componentFactory: KeyguardBouncerComponent.Factory
+ componentFactory: KeyguardBouncerComponent.Factory,
+ messageAreaControllerFactory: KeyguardMessageAreaController.Factory,
+ bouncerMessageInteractor: BouncerMessageInteractor,
+ bouncerLogger: BouncerLogger,
+ featureFlags: FeatureFlags,
) {
// Builds the KeyguardSecurityContainerController from bouncer view group.
val securityContainerController: KeyguardSecurityContainerController =
@@ -125,8 +133,16 @@
securityContainerController.onResume(
KeyguardSecurityView.SCREEN_ON
)
+ bouncerLogger.bindingBouncerMessageView()
+ it.bindMessageView(
+ bouncerMessageInteractor,
+ messageAreaControllerFactory,
+ bouncerLogger,
+ featureFlags
+ )
}
} else {
+ bouncerMessageInteractor.onBouncerBeingHidden()
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ false
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
new file mode 100644
index 0000000..02e6765
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.ui.binder
+
+import android.util.TypedValue
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.R
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.KeyguardIndicationController
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/**
+ * Binds a keyguard indication area view to its view-model.
+ *
+ * To use this properly, users should maintain a one-to-one relationship between the [View] and the
+ * view-binding, binding each view only once. It is okay and expected for the same instance of the
+ * view-model to be reused for multiple view/view-binder bindings.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+object KeyguardIndicationAreaBinder {
+
+ /** Binds the view to the view-model, continuing to update the former based on the latter. */
+ @JvmStatic
+ fun bind(
+ view: ViewGroup,
+ viewModel: KeyguardIndicationAreaViewModel,
+ indicationController: KeyguardIndicationController,
+ ): DisposableHandle {
+ val indicationArea: ViewGroup = view.requireViewById(R.id.keyguard_indication_area)
+ indicationController.setIndicationArea(indicationArea)
+
+ val indicationText: TextView = indicationArea.requireViewById(R.id.keyguard_indication_text)
+ val indicationTextBottom: TextView =
+ indicationArea.requireViewById(R.id.keyguard_indication_text_bottom)
+
+ view.clipChildren = false
+ view.clipToPadding = false
+
+ val configurationBasedDimensions = MutableStateFlow(loadFromResources(view))
+ val disposableHandle =
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.alpha.collect { alpha ->
+ view.importantForAccessibility =
+ if (alpha == 0f) {
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ } else {
+ View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+ }
+
+ indicationArea.alpha = alpha
+ }
+ }
+
+ launch {
+ viewModel.indicationAreaTranslationX.collect { translationX ->
+ indicationArea.translationX = translationX
+ }
+ }
+
+ launch {
+ combine(
+ viewModel.isIndicationAreaPadded,
+ configurationBasedDimensions.map { it.indicationAreaPaddingPx },
+ ) { isPadded, paddingIfPaddedPx ->
+ if (isPadded) {
+ paddingIfPaddedPx
+ } else {
+ 0
+ }
+ }
+ .collect { paddingPx ->
+ indicationArea.setPadding(paddingPx, 0, paddingPx, 0)
+ }
+ }
+
+ launch {
+ configurationBasedDimensions
+ .map { it.defaultBurnInPreventionYOffsetPx }
+ .flatMapLatest { defaultBurnInOffsetY ->
+ viewModel.indicationAreaTranslationY(defaultBurnInOffsetY)
+ }
+ .collect { translationY -> indicationArea.translationY = translationY }
+ }
+
+ launch {
+ configurationBasedDimensions.collect { dimensions ->
+ indicationText.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ dimensions.indicationTextSizePx.toFloat(),
+ )
+ indicationTextBottom.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ dimensions.indicationTextSizePx.toFloat(),
+ )
+ }
+ }
+
+ launch {
+ viewModel.configurationChange.collect {
+ configurationBasedDimensions.value = loadFromResources(view)
+ }
+ }
+ }
+ }
+ return disposableHandle
+ }
+
+ private fun loadFromResources(view: View): ConfigurationBasedDimensions {
+ return ConfigurationBasedDimensions(
+ defaultBurnInPreventionYOffsetPx =
+ view.resources.getDimensionPixelOffset(R.dimen.default_burn_in_prevention_offset),
+ indicationAreaPaddingPx =
+ view.resources.getDimensionPixelOffset(R.dimen.keyguard_indication_area_padding),
+ indicationTextSizePx =
+ view.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.text_size_small_material,
+ ),
+ )
+ }
+
+ private data class ConfigurationBasedDimensions(
+ val defaultBurnInPreventionYOffsetPx: Int,
+ val indicationAreaPaddingPx: Int,
+ val indicationTextSizePx: Int,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt
new file mode 100644
index 0000000..890d565
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.ui.view
+
+import android.content.Context
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+
+class KeyguardIndicationArea(
+ context: Context,
+ private val attrs: AttributeSet?,
+) :
+ LinearLayout(
+ context,
+ attrs,
+ ) {
+
+ init {
+ setId(R.id.keyguard_indication_area)
+ orientation = LinearLayout.VERTICAL
+
+ addView(indicationTopRow(), LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
+ addView(
+ indicationBottomRow(),
+ LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
+ gravity = Gravity.CENTER_HORIZONTAL
+ }
+ )
+ }
+
+ private fun indicationTopRow(): KeyguardIndicationTextView {
+ return KeyguardIndicationTextView(context, attrs).apply {
+ id = R.id.keyguard_indication_text
+ gravity = Gravity.CENTER
+ accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE
+ setTextAppearance(R.style.TextAppearance_Keyguard_BottomArea)
+
+ val padding = R.dimen.keyguard_indication_text_padding.dp()
+ setPaddingRelative(padding, 0, padding, 0)
+ }
+ }
+
+ private fun indicationBottomRow(): KeyguardIndicationTextView {
+ return KeyguardIndicationTextView(context, attrs).apply {
+ id = R.id.keyguard_indication_text_bottom
+ gravity = Gravity.CENTER
+ accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE
+
+ setTextAppearance(R.style.TextAppearance_Keyguard_BottomArea)
+ setEllipsize(TextUtils.TruncateAt.END)
+ setAlpha(0.8f)
+ setMinHeight(R.dimen.keyguard_indication_text_min_height.dp())
+ setMaxLines(2)
+ setVisibility(View.GONE)
+
+ val padding = R.dimen.keyguard_indication_text_padding.dp()
+ setPaddingRelative(padding, 0, padding, 0)
+ }
+ }
+
+ private fun Int.dp(): Int {
+ return context.resources.getDimensionPixelSize(this)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
new file mode 100644
index 0000000..abf0e80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.FrameLayout
+import com.android.systemui.R
+
+/** Provides a container for all keyguard ui content. */
+class KeyguardRootView(
+ context: Context,
+ private val attrs: AttributeSet?,
+) :
+ FrameLayout(
+ context,
+ attrs,
+ ) {
+
+ init {
+ addIndicationTextArea()
+ }
+
+ private fun addIndicationTextArea() {
+ val view = KeyguardIndicationArea(context, attrs)
+ addView(
+ view,
+ FrameLayout.LayoutParams(
+ MATCH_PARENT,
+ WRAP_CONTENT,
+ )
+ .apply {
+ gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ bottomMargin = R.dimen.keyguard_indication_margin_bottom.dp()
+ }
+ )
+ }
+
+ private fun Int.dp(): Int {
+ return context.resources.getDimensionPixelSize(this)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 62a1a9e..3e6f8e6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -57,7 +57,7 @@
* in the wallpaper picker application. This should _always_ be `false` for the real lock screen
* experience.
*/
- private val previewMode = MutableStateFlow(PreviewMode())
+ val previewMode = MutableStateFlow(PreviewMode())
/**
* ID of the slot that's currently selected in the preview that renders exclusively in the
@@ -101,12 +101,6 @@
bottomAreaInteractor.alpha.distinctUntilChanged()
}
}
- /** An observable for whether the indication area should be padded. */
- val isIndicationAreaPadded: Flow<Boolean> =
- combine(startButton, endButton) { startButtonModel, endButtonModel ->
- startButtonModel.isVisible || endButtonModel.isVisible
- }
- .distinctUntilChanged()
/** An observable for the x-offset by which the indication area should be translated. */
val indicationAreaTranslationX: Flow<Float> =
bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
new file mode 100644
index 0000000..389cf76
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.ui.viewmodel
+
+import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/** View-model for the keyguard indication area view */
+@OptIn(ExperimentalCoroutinesApi::class)
+class KeyguardIndicationAreaViewModel
+@Inject
+constructor(
+ private val keyguardInteractor: KeyguardInteractor,
+ private val bottomAreaInteractor: KeyguardBottomAreaInteractor,
+ private val keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel,
+ private val burnInHelperWrapper: BurnInHelperWrapper,
+) {
+
+ /** Notifies when a new configuration is set */
+ val configurationChange: Flow<Unit> = keyguardInteractor.configurationChange
+
+ /** An observable for the alpha level for the entire bottom area. */
+ val alpha: Flow<Float> = keyguardBottomAreaViewModel.alpha
+
+ /** An observable for whether the indication area should be padded. */
+ val isIndicationAreaPadded: Flow<Boolean> =
+ combine(keyguardBottomAreaViewModel.startButton, keyguardBottomAreaViewModel.endButton) {
+ startButtonModel,
+ endButtonModel ->
+ startButtonModel.isVisible || endButtonModel.isVisible
+ }
+ .distinctUntilChanged()
+ /** An observable for the x-offset by which the indication area should be translated. */
+ val indicationAreaTranslationX: Flow<Float> =
+ bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
+
+ /** Returns an observable for the y-offset by which the indication area should be translated. */
+ fun indicationAreaTranslationY(defaultBurnInOffset: Int): Flow<Float> {
+ return keyguardInteractor.dozeAmount
+ .map { dozeAmount ->
+ dozeAmount *
+ (burnInHelperWrapper.burnInOffset(
+ /* amplitude = */ defaultBurnInOffset * 2,
+ /* xAxis= */ false,
+ ) - defaultBurnInOffset)
+ }
+ .distinctUntilChanged()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index e524189..cfb581b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -22,6 +22,7 @@
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadFourFingerSwipe;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadMultiFingerSwipe;
+import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -39,6 +40,7 @@
import android.graphics.Region;
import android.hardware.input.InputManager;
import android.icu.text.SimpleDateFormat;
+import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -197,6 +199,7 @@
private final ViewConfiguration mViewConfiguration;
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
+ private final InputManager mInputManager;
private final Optional<Pip> mPipOptional;
private final Optional<DesktopMode> mDesktopModeOptional;
private final FalsingManager mFalsingManager;
@@ -208,6 +211,7 @@
private final int mDisplayId;
private final Executor mMainExecutor;
+ private final Handler mMainHandler;
private final Executor mBackgroundExecutor;
private final Rect mPipExcludedBounds = new Rect();
@@ -252,6 +256,8 @@
private boolean mIsAttached;
private boolean mIsGesturalModeEnabled;
+ private boolean mIsTrackpadConnected;
+ private boolean mUsingThreeButtonNav;
private boolean mIsEnabled;
private boolean mIsNavBarShownTransiently;
private boolean mIsBackGestureAllowed;
@@ -351,12 +357,48 @@
}
};
+ private final InputManager.InputDeviceListener mInputDeviceListener =
+ new InputManager.InputDeviceListener() {
+
+ // Only one trackpad can be connected to a device at a time, since it takes over the
+ // only USB port.
+ private int mTrackpadDeviceId;
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ if (isTrackpadDevice(deviceId)) {
+ mTrackpadDeviceId = deviceId;
+ update(true /* isTrackpadConnected */);
+ }
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) { }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ if (mTrackpadDeviceId == deviceId) {
+ update(false /* isTrackpadConnected */);
+ }
+ }
+
+ private void update(boolean isTrackpadConnected) {
+ boolean isPreviouslyTrackpadConnected = mIsTrackpadConnected;
+ mIsTrackpadConnected = isTrackpadConnected;
+ if (isPreviouslyTrackpadConnected != mIsTrackpadConnected) {
+ updateIsEnabled();
+ updateCurrentUserResources();
+ }
+ }
+ };
+
EdgeBackGestureHandler(
Context context,
OverviewProxyService overviewProxyService,
SysUiState sysUiState,
PluginManager pluginManager,
@Main Executor executor,
+ @Main Handler handler,
@Background Executor backgroundExecutor,
UserTracker userTracker,
ProtoTracer protoTracer,
@@ -365,6 +407,7 @@
ViewConfiguration viewConfiguration,
WindowManager windowManager,
IWindowManager windowManagerService,
+ InputManager inputManager,
Optional<Pip> pipOptional,
Optional<DesktopMode> desktopModeOptional,
FalsingManager falsingManager,
@@ -375,6 +418,7 @@
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = executor;
+ mMainHandler = handler;
mBackgroundExecutor = backgroundExecutor;
mUserTracker = userTracker;
mOverviewProxyService = overviewProxyService;
@@ -386,6 +430,7 @@
mViewConfiguration = viewConfiguration;
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
+ mInputManager = inputManager;
mPipOptional = pipOptional;
mDesktopModeOptional = desktopModeOptional;
mFalsingManager = falsingManager;
@@ -394,6 +439,8 @@
mFeatureFlags = featureFlags;
mLightBarControllerProvider = lightBarControllerProvider;
mLastReportedConfig.setTo(mContext.getResources().getConfiguration());
+ mIsTrackpadGestureFeaturesEnabled = mFeatureFlags.isEnabled(
+ Flags.TRACKPAD_GESTURE_FEATURES);
ComponentName recentsComponentName = ComponentName.unflattenFromString(
context.getString(com.android.internal.R.string.config_recentsComponentName));
if (recentsComponentName != null) {
@@ -425,7 +472,7 @@
ViewConfiguration.getLongPressTimeout());
mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(
- mContext.getMainThreadHandler(), mContext, this::onNavigationSettingsChanged);
+ mMainHandler, mContext, this::onNavigationSettingsChanged);
updateCurrentUserResources();
}
@@ -512,6 +559,15 @@
mProtoTracer.add(this);
mOverviewProxyService.addCallback(mQuickSwitchListener);
mSysUiState.addCallback(mSysUiStateCallback);
+ if (mIsTrackpadGestureFeaturesEnabled) {
+ mInputManager.registerInputDeviceListener(mInputDeviceListener, mMainHandler);
+ int [] inputDevices = mInputManager.getInputDeviceIds();
+ for (int inputDeviceId : inputDevices) {
+ if (isTrackpadDevice(inputDeviceId)) {
+ mIsTrackpadConnected = true;
+ }
+ }
+ }
updateIsEnabled();
mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
}
@@ -524,6 +580,7 @@
mProtoTracer.remove(this);
mOverviewProxyService.removeCallback(mQuickSwitchListener);
mSysUiState.removeCallback(mSysUiStateCallback);
+ mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
updateIsEnabled();
mUserTracker.removeCallback(mUserChangedCallback);
}
@@ -532,7 +589,9 @@
* @see NavigationModeController.ModeChangedListener#onNavigationModeChanged
*/
public void onNavigationModeChanged(int mode) {
- mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode);
+ mUsingThreeButtonNav = QuickStepContract.isLegacyMode(mode);
+ mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode) || (
+ mIsTrackpadGestureFeaturesEnabled && mUsingThreeButtonNav && mIsTrackpadConnected);
updateIsEnabled();
updateCurrentUserResources();
}
@@ -622,8 +681,6 @@
// Add a nav bar panel window
mIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE);
- mIsTrackpadGestureFeaturesEnabled = mFeatureFlags.isEnabled(
- Flags.TRACKPAD_GESTURE_FEATURES);
resetEdgeBackPlugin();
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
@@ -827,6 +884,12 @@
mDisplaySize.y - insets.bottom);
}
+ private boolean isTrackpadDevice(int deviceId) {
+ InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+ return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
+ | InputDevice.SOURCE_TOUCHPAD);
+ }
+
private boolean desktopExcludeRegionContains(int x, int y) {
return mDesktopModeExcludeRegion.contains(x, y);
}
@@ -951,17 +1014,21 @@
mMLResults = 0;
mLogGesture = false;
mInRejectedExclusion = false;
- // Trackpad back gestures don't have zones, so we don't need to check if the down event
- // is within insets. Also we don't allow back for button press from the trackpad, and
- // yet we do with a mouse.
boolean isWithinInsets = isWithinInsets((int) ev.getX(), (int) ev.getY());
- mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed
- && !isButtonPressFromTrackpad(ev)
- && (isTrackpadMultiFingerSwipe || isWithinInsets)
+ boolean isBackAllowedCommon = !mDisabledForQuickstep && mIsBackGestureAllowed
&& !mGestureBlockingActivityRunning
&& !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
- && (isValidTrackpadBackGesture(isTrackpadMultiFingerSwipe)
- || isWithinTouchRegion((int) ev.getX(), (int) ev.getY()));
+ && !isTrackpadScroll(mIsTrackpadGestureFeaturesEnabled, ev);
+ if (isTrackpadMultiFingerSwipe) {
+ // Trackpad back gestures don't have zones, so we don't need to check if the down
+ // event is within insets.
+ mAllowGesture = isBackAllowedCommon && isValidTrackpadBackGesture(
+ isTrackpadMultiFingerSwipe);
+ } else {
+ mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
+ && isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
+ && !isButtonPressFromTrackpad(ev);
+ }
if (mAllowGesture) {
mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
mEdgeBackPlugin.onMotionEvent(ev);
@@ -1070,6 +1137,7 @@
}
private boolean isButtonPressFromTrackpad(MotionEvent ev) {
+ // We don't allow back for button press from the trackpad, and yet we do with a mouse.
int sources = InputManager.getInstance().getInputDevice(ev.getDeviceId()).getSources();
return (sources & (SOURCE_MOUSE | SOURCE_TOUCHPAD)) == sources && ev.getButtonState() != 0;
}
@@ -1193,6 +1261,8 @@
pw.println(" mPredictionLog=" + String.join("\n", mPredictionLog));
pw.println(" mGestureLogInsideInsets=" + String.join("\n", mGestureLogInsideInsets));
pw.println(" mGestureLogOutsideInsets=" + String.join("\n", mGestureLogOutsideInsets));
+ pw.println(" mIsTrackpadConnected=" + mIsTrackpadConnected);
+ pw.println(" mUsingThreeButtonNav=" + mUsingThreeButtonNav);
pw.println(" mEdgeBackPlugin=" + mEdgeBackPlugin);
if (mEdgeBackPlugin != null) {
mEdgeBackPlugin.dump(pw);
@@ -1242,6 +1312,7 @@
private final SysUiState mSysUiState;
private final PluginManager mPluginManager;
private final Executor mExecutor;
+ private final Handler mHandler;
private final Executor mBackgroundExecutor;
private final UserTracker mUserTracker;
private final ProtoTracer mProtoTracer;
@@ -1250,6 +1321,7 @@
private final ViewConfiguration mViewConfiguration;
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
+ private final InputManager mInputManager;
private final Optional<Pip> mPipOptional;
private final Optional<DesktopMode> mDesktopModeOptional;
private final FalsingManager mFalsingManager;
@@ -1264,6 +1336,7 @@
SysUiState sysUiState,
PluginManager pluginManager,
@Main Executor executor,
+ @Main Handler handler,
@Background Executor backgroundExecutor,
UserTracker userTracker,
ProtoTracer protoTracer,
@@ -1272,6 +1345,7 @@
ViewConfiguration viewConfiguration,
WindowManager windowManager,
IWindowManager windowManagerService,
+ InputManager inputManager,
Optional<Pip> pipOptional,
Optional<DesktopMode> desktopModeOptional,
FalsingManager falsingManager,
@@ -1284,6 +1358,7 @@
mSysUiState = sysUiState;
mPluginManager = pluginManager;
mExecutor = executor;
+ mHandler = handler;
mBackgroundExecutor = backgroundExecutor;
mUserTracker = userTracker;
mProtoTracer = protoTracer;
@@ -1292,6 +1367,7 @@
mViewConfiguration = viewConfiguration;
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
+ mInputManager = inputManager;
mPipOptional = pipOptional;
mDesktopModeOptional = desktopModeOptional;
mFalsingManager = falsingManager;
@@ -1309,6 +1385,7 @@
mSysUiState,
mPluginManager,
mExecutor,
+ mHandler,
mBackgroundExecutor,
mUserTracker,
mProtoTracer,
@@ -1317,6 +1394,7 @@
mViewConfiguration,
mWindowManager,
mWindowManagerService,
+ mInputManager,
mPipOptional,
mDesktopModeOptional,
mFalsingManager,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java
index 50e8aa7..bf5e442 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java
@@ -17,11 +17,18 @@
package com.android.systemui.navigationbar.gestural;
import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
+import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
import android.view.MotionEvent;
public final class Utilities {
+ public static boolean isTrackpadScroll(boolean isTrackpadGestureFeaturesEnabled,
+ MotionEvent event) {
+ return isTrackpadGestureFeaturesEnabled
+ && event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE;
+ }
+
public static boolean isTrackpadMultiFingerSwipe(boolean isTrackpadGestureFeaturesEnabled,
MotionEvent event) {
return isTrackpadGestureFeaturesEnabled
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
new file mode 100644
index 0000000..3e947d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.notetask;
+
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+
+/** A service to help with controlling the state of notes app bubble through the system user. */
+interface INoteTaskBubblesService {
+
+ boolean areBubblesAvailable();
+
+ void showOrHideAppBubble(in Intent intent, in UserHandle userHandle, in Icon icon);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
new file mode 100644
index 0000000..ec205f8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.notetask
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.IBinder
+import android.os.UserHandle
+import com.android.internal.infra.ServiceConnector
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.DebugLogger.debugLog
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import javax.inject.Inject
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+/**
+ * A utility class to help interact with [Bubbles] as system user. The SysUI instance running as
+ * system user is the only instance that has the instance of [Bubbles] that manages the notes app
+ * bubble for all users.
+ *
+ * <p>Note: This class is made overridable so that a fake can be created for as mocking suspending
+ * functions is not supported by the Android tree's version of mockito.
+ */
+@SysUISingleton
+open class NoteTaskBubblesController
+@Inject
+constructor(
+ @Application private val context: Context,
+ @Background private val bgDispatcher: CoroutineDispatcher
+) {
+
+ private val serviceConnector: ServiceConnector<INoteTaskBubblesService> =
+ ServiceConnector.Impl(
+ context,
+ Intent(context, NoteTaskBubblesService::class.java),
+ Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+ UserHandle.USER_SYSTEM,
+ INoteTaskBubblesService.Stub::asInterface
+ )
+
+ /** Returns whether notes app bubble is supported. */
+ open suspend fun areBubblesAvailable(): Boolean =
+ withContext(bgDispatcher) {
+ suspendCoroutine { continuation ->
+ serviceConnector
+ .postForResult { it.areBubblesAvailable() }
+ .whenComplete { available, error ->
+ if (error != null) {
+ debugLog(error = error) { "Failed to query Bubbles as system user." }
+ }
+ continuation.resume(available ?: false)
+ }
+ }
+ }
+
+ /** Calls the [Bubbles.showOrHideAppBubble] API as [UserHandle.USER_SYSTEM]. */
+ open suspend fun showOrHideAppBubble(
+ intent: Intent,
+ userHandle: UserHandle,
+ icon: Icon
+ ) {
+ withContext(bgDispatcher) {
+ serviceConnector
+ .post { it.showOrHideAppBubble(intent, userHandle, icon) }
+ .whenComplete { _, error ->
+ if (error != null) {
+ debugLog(error = error) {
+ "Failed to show notes app bubble for intent $intent, " +
+ "user $userHandle, and icon $icon."
+ }
+ } else {
+ debugLog {
+ "Call to show notes app bubble for intent $intent, " +
+ "user $userHandle, and icon $icon successful."
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * A helper service to call [Bubbles] APIs that should always be called from the system user
+ * instance of SysUI.
+ *
+ * <p>Note: This service always runs in the SysUI process running on the system user
+ * irrespective of which user started the service. This is required so that the correct instance
+ * of {@link Bubbles} is injected. This is set via attribute {@code android:singleUser=”true”}
+ * in AndroidManifest.
+ */
+ class NoteTaskBubblesService
+ @Inject
+ constructor(private val mOptionalBubbles: Optional<Bubbles>) : Service() {
+
+ override fun onBind(intent: Intent): IBinder {
+ return object : INoteTaskBubblesService.Stub() {
+ override fun areBubblesAvailable() = mOptionalBubbles.isPresent
+
+ override fun showOrHideAppBubble(
+ intent: Intent,
+ userHandle: UserHandle,
+ icon: Icon
+ ) {
+ mOptionalBubbles.ifPresentOrElse(
+ { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
+ {
+ debugLog {
+ "Failed to show or hide bubble for intent $intent," +
+ "user $user, and icon $icon as bubble is empty."
+ }
+ }
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 25272ae..efbec29 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -33,25 +33,27 @@
import android.graphics.drawable.Icon
import android.os.UserHandle
import android.os.UserManager
+import android.provider.Settings
import android.widget.Toast
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
-import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
import com.android.systemui.util.kotlin.getOrNull
+import com.android.systemui.util.settings.SecureSettings
import com.android.wm.shell.bubbles.Bubble
-import com.android.wm.shell.bubbles.Bubbles
import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener
-import java.util.Optional
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
/**
* Entry point for creating and managing note.
@@ -69,13 +71,15 @@
private val shortcutManager: ShortcutManager,
private val resolver: NoteTaskInfoResolver,
private val eventLogger: NoteTaskEventLogger,
- private val optionalBubbles: Optional<Bubbles>,
+ private val noteTaskBubblesController: NoteTaskBubblesController,
private val userManager: UserManager,
private val keyguardManager: KeyguardManager,
private val activityManager: ActivityManager,
@NoteTaskEnabledKey private val isEnabled: Boolean,
private val devicePolicyManager: DevicePolicyManager,
private val userTracker: UserTracker,
+ private val secureSettings: SecureSettings,
+ @Application private val applicationScope: CoroutineScope
) {
@VisibleForTesting val infoReference = AtomicReference<NoteTaskInfo?>()
@@ -100,18 +104,6 @@
}
}
- /** Starts [LaunchNoteTaskProxyActivity] on the given [user]. */
- fun startNoteTaskProxyActivityForUser(user: UserHandle) {
- context.startActivityAsUser(
- Intent().apply {
- component =
- ComponentName(context, LaunchNoteTaskManagedProfileProxyActivity::class.java)
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- },
- user
- )
- }
-
/** Starts the notes role setting. */
fun startNotesRoleSetting(activityContext: Context, entryPoint: NoteTaskEntryPoint?) {
val user =
@@ -146,7 +138,7 @@
userTracker.userProfiles.firstOrNull { userManager.isManagedProfile(it.id) }?.userHandle
?: userTracker.userHandle
} else {
- userTracker.userHandle
+ secureSettings.preferredUser
}
/**
@@ -175,7 +167,19 @@
) {
if (!isEnabled) return
- val bubbles = optionalBubbles.getOrNull() ?: return
+ applicationScope.launch { awaitShowNoteTaskAsUser(entryPoint, user) }
+ }
+
+ private suspend fun awaitShowNoteTaskAsUser(
+ entryPoint: NoteTaskEntryPoint,
+ user: UserHandle,
+ ) {
+ if (!isEnabled) return
+
+ if (!noteTaskBubblesController.areBubblesAvailable()) {
+ debugLog { "Bubbles not available in the system user SysUI instance" }
+ return
+ }
// TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
if (!userManager.isUserUnlocked) return
@@ -210,7 +214,7 @@
val intent = createNoteTaskIntent(info)
val icon =
Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
- bubbles.showOrHideAppBubble(intent, user, icon)
+ noteTaskBubblesController.showOrHideAppBubble(intent, user, icon)
// App bubble logging happens on `onBubbleExpandChanged`.
debugLog { "onShowNoteTask - opened as app bubble: $info" }
}
@@ -284,15 +288,55 @@
}
/**
+ * Like [updateNoteTaskAsUser] but automatically apply to the current user and all its work
+ * profiles.
+ *
+ * @see updateNoteTaskAsUser
+ * @see UserTracker.userHandle
+ * @see UserTracker.userProfiles
+ */
+ fun updateNoteTaskForCurrentUserAndManagedProfiles() {
+ updateNoteTaskAsUser(userTracker.userHandle)
+ for (profile in userTracker.userProfiles) {
+ if (userManager.isManagedProfile(profile.id)) {
+ updateNoteTaskAsUser(profile.userHandle)
+ }
+ }
+ }
+
+ /**
* Updates all [NoteTaskController] related information, including but not exclusively the
* widget shortcut created by the [user] - by default it will use the current user.
*
+ * If the user is not current user, the update will be dispatched to run in that user's process.
+ *
* Keep in mind the shortcut API has a
* [rate limiting](https://developer.android.com/develop/ui/views/launch/shortcuts/managing-shortcuts#rate-limiting)
* and may not be updated in real-time. To reduce the chance of stale shortcuts, we run the
* function during System UI initialization.
*/
fun updateNoteTaskAsUser(user: UserHandle) {
+ if (!userManager.isUserUnlocked(user)) {
+ debugLog { "updateNoteTaskAsUser call but user locked: user=$user" }
+ return
+ }
+
+ if (user == userTracker.userHandle) {
+ updateNoteTaskAsUserInternal(user)
+ } else {
+ // TODO(b/278729185): Replace fire and forget service with a bounded service.
+ val intent = NoteTaskControllerUpdateService.createIntent(context)
+ context.startServiceAsUser(intent, user)
+ }
+ }
+
+ @InternalNoteTaskApi
+ fun updateNoteTaskAsUserInternal(user: UserHandle) {
+ if (!userManager.isUserUnlocked(user)) {
+ debugLog { "updateNoteTaskAsUserInternal call but user locked: user=$user" }
+ return
+ }
+
val packageName = roleManager.getDefaultRoleHolderAsUser(ROLE_NOTES, user)
val hasNotesRoleHolder = isEnabled && !packageName.isNullOrEmpty()
@@ -310,20 +354,20 @@
/** @see OnRoleHoldersChangedListener */
fun onRoleHoldersChanged(roleName: String, user: UserHandle) {
if (roleName != ROLE_NOTES) return
- if (!userManager.isUserUnlocked(user)) {
- debugLog { "onRoleHoldersChanged call but user locked: role=$roleName, user=$user" }
- return
- }
- if (user == userTracker.userHandle) {
- updateNoteTaskAsUser(user)
- } else {
- // TODO(b/278729185): Replace fire and forget service with a bounded service.
- val intent = NoteTaskControllerUpdateService.createIntent(context)
- context.startServiceAsUser(intent, user)
- }
+ updateNoteTaskAsUser(user)
}
+ private val SecureSettings.preferredUser: UserHandle
+ get() {
+ val userId =
+ secureSettings.getInt(
+ Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
+ userTracker.userHandle.identifier,
+ )
+ return UserHandle.of(userId)
+ }
+
companion object {
val TAG = NoteTaskController::class.simpleName.orEmpty()
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt
index 26b35cc..3e352af 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt
@@ -44,7 +44,7 @@
override fun onCreate() {
super.onCreate()
// TODO(b/278729185): Replace fire and forget service with a bounded service.
- controller.updateNoteTaskAsUser(user)
+ controller.updateNoteTaskAsUserInternal(user)
stopSelf()
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index 221ff65..fe1034a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -15,7 +15,10 @@
*/
package com.android.systemui.notetask
+import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
+import android.content.Context
+import android.content.pm.UserInfo
import android.os.UserHandle
import android.view.KeyEvent
import android.view.KeyEvent.KEYCODE_N
@@ -54,6 +57,7 @@
initializeHandleSystemKey()
initializeOnRoleHoldersChanged()
initializeOnUserUnlocked()
+ initializeUserTracker()
}
/**
@@ -79,7 +83,7 @@
private fun initializeOnRoleHoldersChanged() {
roleManager.addOnRoleHoldersChangedListenerAsUser(
backgroundExecutor,
- controller::onRoleHoldersChanged,
+ callbacks,
UserHandle.ALL,
)
}
@@ -93,18 +97,41 @@
*/
private fun initializeOnUserUnlocked() {
if (keyguardUpdateMonitor.isUserUnlocked(userTracker.userId)) {
- controller.setNoteTaskShortcutEnabled(true, userTracker.userHandle)
- } else {
- keyguardUpdateMonitor.registerCallback(onUserUnlockedCallback)
+ controller.updateNoteTaskForCurrentUserAndManagedProfiles()
}
+ keyguardUpdateMonitor.registerCallback(callbacks)
}
- // KeyguardUpdateMonitor.registerCallback uses a weak reference, so we need a hard reference.
- private val onUserUnlockedCallback =
- object : KeyguardUpdateMonitorCallback() {
+ private fun initializeUserTracker() {
+ userTracker.addCallback(callbacks, backgroundExecutor)
+ }
+
+ // Some callbacks use a weak reference, so we play safe and keep a hard reference to them all.
+ private val callbacks =
+ object :
+ KeyguardUpdateMonitorCallback(),
+ CommandQueue.Callbacks,
+ UserTracker.Callback,
+ OnRoleHoldersChangedListener {
+
+ override fun handleSystemKey(key: KeyEvent) {
+ key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
+ }
+
+ override fun onRoleHoldersChanged(roleName: String, user: UserHandle) {
+ controller.onRoleHoldersChanged(roleName, user)
+ }
+
override fun onUserUnlocked() {
- controller.setNoteTaskShortcutEnabled(true, userTracker.userHandle)
- keyguardUpdateMonitor.removeCallback(this)
+ controller.updateNoteTaskForCurrentUserAndManagedProfiles()
+ }
+
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ controller.updateNoteTaskForCurrentUserAndManagedProfiles()
+ }
+
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ controller.updateNoteTaskForCurrentUserAndManagedProfiles()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 109cfee..c0e688f 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -26,7 +26,6 @@
import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceModule
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
-import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -40,12 +39,12 @@
@[Binds IntoMap ClassKey(NoteTaskControllerUpdateService::class)]
fun NoteTaskControllerUpdateService.bindNoteTaskControllerUpdateService(): Service
+ @[Binds IntoMap ClassKey(NoteTaskBubblesController.NoteTaskBubblesService::class)]
+ fun NoteTaskBubblesController.NoteTaskBubblesService.bindNoteTaskBubblesService(): Service
+
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
fun LaunchNoteTaskActivity.bindNoteTaskLauncherActivity(): Activity
- @[Binds IntoMap ClassKey(LaunchNoteTaskManagedProfileProxyActivity::class)]
- fun LaunchNoteTaskManagedProfileProxyActivity.bindNoteTaskLauncherProxyActivity(): Activity
-
@[Binds IntoMap ClassKey(LaunchNotesRoleSettingsTrampolineActivity::class)]
fun LaunchNotesRoleSettingsTrampolineActivity.bindLaunchNotesRoleSettingsTrampolineActivity():
Activity
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
index 441b9f5..a2ebead 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
@@ -19,6 +19,7 @@
import android.app.role.RoleManager
import android.app.role.RoleManager.ROLE_NOTES
import android.content.Context
+import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.graphics.drawable.Icon
import android.os.PersistableBundle
@@ -42,20 +43,41 @@
context: Context,
user: UserHandle,
): ShortcutInfo {
+ val packageName = getDefaultRoleHolderAsUser(ROLE_NOTES, user)
+
val extras = PersistableBundle()
- getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName ->
+ if (packageName != null) {
// Set custom app badge using the icon from ROLES_NOTES default app.
extras.putString(NoteTaskController.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName)
}
+ val shortLabel = context.getString(R.string.note_task_button_label)
+
+ val applicationLabel = context.packageManager.getApplicationLabel(packageName)
+ val longLabel =
+ if (applicationLabel == null) {
+ shortLabel
+ } else {
+ context.getString(
+ R.string.note_task_shortcut_long_label,
+ applicationLabel,
+ )
+ }
+
val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
return ShortcutInfo.Builder(context, NoteTaskController.SHORTCUT_ID)
.setIntent(LaunchNoteTaskActivity.newIntent(context = context))
- .setShortLabel(context.getString(R.string.note_task_button_label))
+ .setShortLabel(shortLabel)
+ .setLongLabel(longLabel)
.setLongLived(true)
.setIcon(icon)
.setExtras(extras)
.build()
}
+
+ private fun PackageManager.getApplicationLabel(packageName: String?): String? =
+ runCatching { getApplicationInfo(packageName, /* flags= */ 0)!! }
+ .getOrNull()
+ ?.let { info -> getApplicationLabel(info).toString() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
index 8ca13b9..493330a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
@@ -19,61 +19,18 @@
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.os.UserHandle
-import android.os.UserManager
import androidx.activity.ComponentActivity
-import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
-import com.android.systemui.settings.UserTracker
import javax.inject.Inject
/** Activity responsible for launching the note experience, and finish. */
-class LaunchNoteTaskActivity
-@Inject
-constructor(
- private val controller: NoteTaskController,
- private val userManager: UserManager,
- private val userTracker: UserTracker,
-) : ComponentActivity() {
+class LaunchNoteTaskActivity @Inject constructor(private val controller: NoteTaskController) :
+ ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
- // Under the hood, notes app shortcuts are shown in a floating window, called Bubble.
- // Bubble API is only available in the main user but not work profile.
- //
- // On devices with work profile (WP), SystemUI provides both personal notes app shortcuts &
- // work profile notes app shortcuts. In order to make work profile notes app shortcuts to
- // show in Bubble, a few redirections across users are required:
- // 1. When `LaunchNoteTaskActivity` is started in the work profile user, we launch
- // `LaunchNoteTaskManagedProfileProxyActivity` on the main user, which has access to the
- // Bubble API.
- // 2. `LaunchNoteTaskManagedProfileProxyActivity` calls `Bubble#showOrHideAppBubble` with
- // the work profile user ID.
- // 3. Bubble renders the work profile notes app activity in a floating window, which is
- // hosted in the main user.
- //
- // WP main user
- // ------------------------ -------------------------------------------
- // | LaunchNoteTaskActivity | -> | LaunchNoteTaskManagedProfileProxyActivity |
- // ------------------------ -------------------------------------------
- // |
- // main user |
- // ---------------------------- |
- // | Bubble#showOrHideAppBubble | <--------------
- // | (with WP user ID) |
- // ----------------------------
- val mainUser: UserHandle? = userManager.mainUser
- if (userManager.isManagedProfile) {
- if (mainUser == null) {
- debugLog { "Can't find the main user. Skipping the notes app launch." }
- } else {
- controller.startNoteTaskProxyActivityForUser(mainUser)
- }
- } else {
- controller.showNoteTask(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT)
- }
+ controller.showNoteTaskAsUser(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT, user)
finish()
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivity.kt
deleted file mode 100644
index 3259b0d..0000000
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivity.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.notetask.shortcut
-
-import android.os.Build
-import android.os.Bundle
-import android.os.UserManager
-import android.util.Log
-import androidx.activity.ComponentActivity
-import com.android.systemui.notetask.NoteTaskController
-import com.android.systemui.notetask.NoteTaskEntryPoint
-import com.android.systemui.settings.UserTracker
-import javax.inject.Inject
-
-/**
- * An internal proxy activity that starts notes app in the work profile.
- *
- * If there is no work profile, this activity finishes gracefully.
- *
- * This activity MUST NOT be exported because that would expose the INTERACT_ACROSS_USER privilege
- * to any apps.
- */
-class LaunchNoteTaskManagedProfileProxyActivity
-@Inject
-constructor(
- private val controller: NoteTaskController,
- private val userTracker: UserTracker,
- private val userManager: UserManager,
-) : ComponentActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- val managedProfileUser =
- userTracker.userProfiles.firstOrNull { userManager.isManagedProfile(it.id) }
-
- if (managedProfileUser == null) {
- logDebug { "Fail to find the work profile user." }
- } else {
- controller.showNoteTaskAsUser(
- entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT,
- user = managedProfileUser.userHandle
- )
- }
- finish()
- }
-}
-
-private inline fun logDebug(message: () -> String) {
- if (Build.IS_DEBUGGABLE) {
- Log.d(NoteTaskController.TAG, message())
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 380b85c..212a2b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -286,7 +286,6 @@
mHandler.removeCallbacks(mHideProgressBarRunnable);
mHandler.removeCallbacks(mHideSearchingRunnable);
mMobileNetworkLayout.setOnClickListener(null);
- mMobileDataToggle.setOnCheckedChangeListener(null);
mConnectedWifListLayout.setOnClickListener(null);
if (mSecondaryMobileNetworkLayout != null) {
mSecondaryMobileNetworkLayout.setOnClickListener(null);
@@ -351,18 +350,16 @@
}
mInternetDialogController.connectCarrierNetwork();
});
- mMobileDataToggle.setOnCheckedChangeListener(
- (buttonView, isChecked) -> {
- if (!isChecked && shouldShowMobileDialog()) {
- showTurnOffMobileDialog();
- } else if (!shouldShowMobileDialog()) {
- if (mInternetDialogController.isMobileDataEnabled() == isChecked) {
- return;
- }
- mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
- isChecked, false);
- }
- });
+ mMobileDataToggle.setOnClickListener(v -> {
+ boolean isChecked = mMobileDataToggle.isChecked();
+ if (!isChecked && shouldShowMobileDialog()) {
+ mMobileDataToggle.setChecked(true);
+ showTurnOffMobileDialog();
+ } else if (mInternetDialogController.isMobileDataEnabled() != isChecked) {
+ mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
+ isChecked, false);
+ }
+ });
mConnectedWifListLayout.setOnClickListener(this::onClickConnectedWifi);
mSeeAllLayout.setOnClickListener(this::onClickSeeMoreButton);
mWiFiToggle.setOnCheckedChangeListener(
@@ -696,9 +693,7 @@
mAlertDialog = new Builder(mContext)
.setTitle(R.string.mobile_data_disable_title)
.setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
- .setNegativeButton(android.R.string.cancel, (d, w) -> {
- mMobileDataToggle.setChecked(true);
- })
+ .setNegativeButton(android.R.string.cancel, (d, w) -> {})
.setPositiveButton(
com.android.internal.R.string.alert_windows_notification_turn_off_action,
(d, w) -> {
@@ -708,7 +703,6 @@
Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
})
.create();
- mAlertDialog.setOnCancelListener(dialog -> mMobileDataToggle.setChecked(true));
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
SystemUIDialog.registerDismissListener(mAlertDialog);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 07259c2..bb38b30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -200,8 +200,8 @@
// TODO: change the method signature to use (boolean inputFocusTransferStarted)
@Override
- public void onStatusBarMotionEvent(MotionEvent event) {
- verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> {
+ public void onStatusBarTouchEvent(MotionEvent event) {
+ verifyCallerAndClearCallingIdentity("onStatusBarTouchEvent", () -> {
// TODO move this logic to message queue
mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces -> {
if (event.getActionMasked() == ACTION_DOWN) {
@@ -236,6 +236,13 @@
}
@Override
+ public void onStatusBarTrackpadEvent(MotionEvent event) {
+ verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () ->
+ mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces ->
+ centralSurfaces.onStatusBarTrackpadEvent(event)));
+ }
+
+ @Override
public void onBackPressed() {
verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
@@ -345,7 +352,7 @@
@Override
public void expandNotificationPanel() {
- verifyCallerAndClearCallingIdentity("expandNotificationPanel",
+ verifyCallerAndClearCallingIdentityPostMain("expandNotificationPanel",
() -> mCommandQueue.handleSystemKey(new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN)));
}
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
new file mode 100644
index 0000000..8f001ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -0,0 +1,7 @@
+package com.android.systemui.scene.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A root view of the main SysUI window that supports scenes. */
+class SceneWindowRootView(context: Context?, attrs: AttributeSet?) : WindowRootView(context, attrs)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
new file mode 100644
index 0000000..a0f9667
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.scene.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+/** A view that can serve as the root of the main SysUI window. */
+open class WindowRootView(context: Context?, attrs: AttributeSet?) : FrameLayout(context, attrs)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
index afc8bff..7de22b1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
@@ -19,7 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.os.UserManager;
+import android.os.UserHandle;
import androidx.annotation.Nullable;
@@ -39,15 +39,14 @@
private final DisplayTracker mDisplayTracker;
@Inject
- AppClipsCrossProcessHelper(@Application Context context, UserManager userManager,
- DisplayTracker displayTracker) {
+ AppClipsCrossProcessHelper(@Application Context context, DisplayTracker displayTracker) {
// Start a service as main user so that even if the app clips activity is running as work
// profile user the service is able to use correct instance of Bubbles to grab a screenshot
// excluding the bubble layer.
mProxyConnector = new ServiceConnector.Impl<>(context,
new Intent(context, AppClipsScreenshotHelperService.class),
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
- | Context.BIND_NOT_VISIBLE, userManager.getMainUser().getIdentifier(),
+ | Context.BIND_NOT_VISIBLE, UserHandle.USER_SYSTEM,
IAppClipsScreenshotHelperService.Stub::asInterface);
mDisplayTracker = displayTracker;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
index 83ff020..e0b9f9b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
@@ -33,6 +33,11 @@
/**
* A helper service that runs in SysUI process and helps {@link AppClipsActivity} which runs in its
* own separate process take a screenshot.
+ *
+ * <p>Note: This service always runs in the SysUI process running on the system user irrespective of
+ * which user started the service. This is required so that the correct instance of {@link Bubbles}
+ * instance is injected. This is set via attribute {@code android:singleUser=”true”} in
+ * AndroidManifest.
*/
public class AppClipsScreenshotHelperService extends Service {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
index 3949492..dce8c81 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
@@ -16,6 +16,11 @@
package com.android.systemui.screenshot.appclips;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
+
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
import android.app.Activity;
@@ -25,17 +30,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.Intent.CaptureContentForNoteStatusCodes;
import android.content.res.Resources;
import android.os.IBinder;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.infra.ServiceConnector;
import com.android.internal.statusbar.IAppClipsService;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Application;
@@ -43,73 +43,36 @@
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
-import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
/**
* A service that communicates with {@link StatusBarManager} to support the
- * {@link StatusBarManager#canLaunchCaptureContentActivityForNote(Activity)} API.
+ * {@link StatusBarManager#canLaunchCaptureContentActivityForNote(Activity)} API. Also used by
+ * {@link AppClipsTrampolineActivity} to query if an app should be allowed to user App Clips.
+ *
+ * <p>Note: This service always runs in the SysUI process running on the system user irrespective of
+ * which user started the service. This is required so that the correct instance of {@link Bubbles}
+ * instance is injected. This is set via attribute {@code android:singleUser=”true”} in
+ * AndroidManifest.
*/
public class AppClipsService extends Service {
- private static final String TAG = AppClipsService.class.getSimpleName();
-
@Application private final Context mContext;
private final FeatureFlags mFeatureFlags;
private final Optional<Bubbles> mOptionalBubbles;
private final DevicePolicyManager mDevicePolicyManager;
- private final UserManager mUserManager;
-
private final boolean mAreTaskAndTimeIndependentPrerequisitesMet;
- @VisibleForTesting()
- @Nullable ServiceConnector<IAppClipsService> mProxyConnectorToMainProfile;
-
@Inject
public AppClipsService(@Application Context context, FeatureFlags featureFlags,
- Optional<Bubbles> optionalBubbles, DevicePolicyManager devicePolicyManager,
- UserManager userManager) {
+ Optional<Bubbles> optionalBubbles, DevicePolicyManager devicePolicyManager) {
mContext = context;
mFeatureFlags = featureFlags;
mOptionalBubbles = optionalBubbles;
mDevicePolicyManager = devicePolicyManager;
- mUserManager = userManager;
-
- // The consumer of this service are apps that call through StatusBarManager API to query if
- // it can use app clips API. Since these apps can be launched as work profile users, this
- // service will start as work profile user. SysUI doesn't share injected instances for
- // different users. This is why the bubbles instance injected will be incorrect. As the apps
- // don't generally have permission to connect to a service running as different user, we
- // start a proxy connection to communicate with the main user's version of this service.
- if (mUserManager.isManagedProfile()) {
- // No need to check for prerequisites in this case as those are incorrect for work
- // profile user instance of the service and the main user version of the service will
- // take care of this check.
- mAreTaskAndTimeIndependentPrerequisitesMet = false;
-
- // Get the main user so that we can connect to the main user's version of the service.
- UserHandle mainUser = mUserManager.getMainUser();
- if (mainUser == null) {
- // If main user is not available there isn't much we can do, no apps can use app
- // clips.
- return;
- }
-
- // Set up the connection to be used later during onBind callback.
- mProxyConnectorToMainProfile =
- new ServiceConnector.Impl<>(
- context,
- new Intent(context, AppClipsService.class),
- Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
- | Context.BIND_NOT_VISIBLE,
- mainUser.getIdentifier(),
- IAppClipsService.Stub::asInterface);
- return;
- }
mAreTaskAndTimeIndependentPrerequisitesMet = checkIndependentVariables();
- mProxyConnectorToMainProfile = null;
}
private boolean checkIndependentVariables() {
@@ -144,40 +107,25 @@
return new IAppClipsService.Stub() {
@Override
public boolean canLaunchCaptureContentActivityForNote(int taskId) {
- // In case of managed profile, use the main user's instance of the service. Callers
- // cannot directly connect to the main user's instance as they may not have the
- // permission to interact across users.
- if (mUserManager.isManagedProfile()) {
- return canLaunchCaptureContentActivityForNoteFromMainUser(taskId);
- }
+ return canLaunchCaptureContentActivityForNoteInternal(taskId)
+ == CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+ }
+ @Override
+ @CaptureContentForNoteStatusCodes
+ public int canLaunchCaptureContentActivityForNoteInternal(int taskId) {
if (!mAreTaskAndTimeIndependentPrerequisitesMet) {
- return false;
+ return CAPTURE_CONTENT_FOR_NOTE_FAILED;
}
if (!mOptionalBubbles.get().isAppBubbleTaskId(taskId)) {
- return false;
+ return CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
}
- return !mDevicePolicyManager.getScreenCaptureDisabled(null);
+ return mDevicePolicyManager.getScreenCaptureDisabled(null)
+ ? CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN
+ : CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
}
};
}
-
- /** Returns whether the app clips API can be used by querying the service as the main user. */
- private boolean canLaunchCaptureContentActivityForNoteFromMainUser(int taskId) {
- if (mProxyConnectorToMainProfile == null) {
- return false;
- }
-
- try {
- AndroidFuture<Boolean> future = mProxyConnectorToMainProfile.postForResult(
- service -> service.canLaunchCaptureContentActivityForNote(taskId));
- return future.get();
- } catch (ExecutionException | InterruptedException e) {
- Log.d(TAG, "Exception from service\n" + e);
- }
-
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
index f00803c..6e5cef4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
@@ -22,41 +22,41 @@
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
-import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
import android.app.Activity;
-import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.Intent.CaptureContentForNoteStatusCodes;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.ResultReceiver;
import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IAppClipsService;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.dagger.qualifiers.Application;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.notetask.NoteTaskController;
import com.android.systemui.notetask.NoteTaskEntryPoint;
-import com.android.systemui.settings.UserTracker;
-import com.android.wm.shell.bubbles.Bubbles;
-import java.util.Optional;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -82,39 +82,57 @@
private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName();
static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI";
- @VisibleForTesting
- static final String EXTRA_USE_WP_USER = TAG + "USE_WP_USER";
static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
- private final DevicePolicyManager mDevicePolicyManager;
- private final FeatureFlags mFeatureFlags;
- private final Optional<Bubbles> mOptionalBubbles;
private final NoteTaskController mNoteTaskController;
private final PackageManager mPackageManager;
- private final UserTracker mUserTracker;
private final UiEventLogger mUiEventLogger;
- private final UserManager mUserManager;
+ private final BroadcastSender mBroadcastSender;
+ @Background
+ private final Executor mBgExecutor;
+ @Main
+ private final Executor mMainExecutor;
private final ResultReceiver mResultReceiver;
+ private final ServiceConnector<IAppClipsService> mAppClipsServiceConnector;
+
+ private UserHandle mUserHandle;
private Intent mKillAppClipsBroadcastIntent;
- private UserHandle mNotesAppUser;
@Inject
- public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags,
- Optional<Bubbles> optionalBubbles, NoteTaskController noteTaskController,
- PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger,
- UserManager userManager, @Main Handler mainHandler) {
- mDevicePolicyManager = devicePolicyManager;
- mFeatureFlags = flags;
- mOptionalBubbles = optionalBubbles;
+ public AppClipsTrampolineActivity(@Application Context context,
+ NoteTaskController noteTaskController, PackageManager packageManager,
+ UiEventLogger uiEventLogger, BroadcastSender broadcastSender,
+ @Background Executor bgExecutor, @Main Executor mainExecutor,
+ @Main Handler mainHandler) {
mNoteTaskController = noteTaskController;
mPackageManager = packageManager;
- mUserTracker = userTracker;
mUiEventLogger = uiEventLogger;
- mUserManager = userManager;
+ mBroadcastSender = broadcastSender;
+ mBgExecutor = bgExecutor;
+ mMainExecutor = mainExecutor;
+
+ mResultReceiver = createResultReceiver(mainHandler);
+ mAppClipsServiceConnector = createServiceConnector(context);
+ }
+
+ /** A constructor used only for testing to verify interactions with {@link ServiceConnector}. */
+ @VisibleForTesting
+ AppClipsTrampolineActivity(ServiceConnector<IAppClipsService> appClipsServiceConnector,
+ NoteTaskController noteTaskController, PackageManager packageManager,
+ UiEventLogger uiEventLogger, BroadcastSender broadcastSender,
+ @Background Executor bgExecutor, @Main Executor mainExecutor,
+ @Main Handler mainHandler) {
+ mAppClipsServiceConnector = appClipsServiceConnector;
+ mNoteTaskController = noteTaskController;
+ mPackageManager = packageManager;
+ mUiEventLogger = uiEventLogger;
+ mBroadcastSender = broadcastSender;
+ mBgExecutor = bgExecutor;
+ mMainExecutor = mainExecutor;
mResultReceiver = createResultReceiver(mainHandler);
}
@@ -127,62 +145,62 @@
return;
}
- if (mUserManager.isManagedProfile()) {
- maybeStartActivityForWPUser();
- finish();
+ mUserHandle = getUser();
+
+ mBgExecutor.execute(() -> {
+ AndroidFuture<Integer> statusCodeFuture = mAppClipsServiceConnector.postForResult(
+ service -> service.canLaunchCaptureContentActivityForNoteInternal(getTaskId()));
+ statusCodeFuture.whenCompleteAsync(this::handleAppClipsStatusCode, mMainExecutor);
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (isFinishing() && mKillAppClipsBroadcastIntent != null) {
+ mBroadcastSender.sendBroadcast(mKillAppClipsBroadcastIntent, PERMISSION_SELF);
+ }
+
+ super.onDestroy();
+ }
+
+ private void handleAppClipsStatusCode(@CaptureContentForNoteStatusCodes int statusCode,
+ Throwable error) {
+ if (isFinishing()) {
+ // It's too late, trampoline activity is finishing or already finished. Return early.
return;
}
- if (!mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)) {
- finish();
+ if (error != null) {
+ Log.d(TAG, "Error querying app clips service", error);
+ setErrorResultAndFinish(statusCode);
return;
}
- if (mOptionalBubbles.isEmpty()) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
- return;
- }
+ switch (statusCode) {
+ case CAPTURE_CONTENT_FOR_NOTE_SUCCESS:
+ launchAppClipsActivity();
+ break;
- if (!mOptionalBubbles.get().isAppBubbleTaskId(getTaskId())) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED);
- return;
+ case CAPTURE_CONTENT_FOR_NOTE_FAILED:
+ case CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED:
+ case CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN:
+ default:
+ setErrorResultAndFinish(statusCode);
}
+ }
- if (mDevicePolicyManager.getScreenCaptureDisabled(null)) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN);
- return;
- }
-
- ComponentName componentName;
- try {
- componentName = ComponentName.unflattenFromString(
+ private void launchAppClipsActivity() {
+ ComponentName componentName = ComponentName.unflattenFromString(
getString(R.string.config_screenshotAppClipsActivityComponent));
- } catch (Resources.NotFoundException e) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
- return;
- }
-
- if (componentName == null || componentName.getPackageName().isEmpty()
- || componentName.getClassName().isEmpty()) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
- return;
- }
-
- mNotesAppUser = getUser();
- if (getIntent().getBooleanExtra(EXTRA_USE_WP_USER, /* defaultValue= */ false)) {
- // Get the work profile user internally instead of passing around via intent extras as
- // this activity is exported apps could potentially mess around with intent extras.
- mNotesAppUser = getWorkProfileUser().orElse(mNotesAppUser);
- }
-
String callingPackageName = getCallingPackage();
- Intent intent = new Intent().setComponent(componentName)
+
+ Intent intent = new Intent()
+ .setComponent(componentName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
.putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
try {
- // Start the App Clips activity for the user corresponding to the notes app user.
- startActivityAsUser(intent, mNotesAppUser);
+ startActivity(intent);
// Set up the broadcast intent that will inform the above App Clips activity to finish
// when this trampoline activity is finished.
@@ -198,39 +216,6 @@
}
}
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- if (isFinishing() && mKillAppClipsBroadcastIntent != null) {
- sendBroadcast(mKillAppClipsBroadcastIntent, PERMISSION_SELF);
- }
- }
-
- private Optional<UserHandle> getWorkProfileUser() {
- return mUserTracker.getUserProfiles().stream()
- .filter(profile -> mUserManager.isManagedProfile(profile.id))
- .findFirst()
- .map(UserInfo::getUserHandle);
- }
-
- private void maybeStartActivityForWPUser() {
- UserHandle mainUser = mUserManager.getMainUser();
- if (mainUser == null) {
- setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
- return;
- }
-
- // Start the activity as the main user with activity result forwarding. Set the intent extra
- // so that the newly started trampoline activity starts the actual app clips activity as the
- // work profile user. Starting the app clips activity as the work profile user is required
- // to save the screenshot in work profile user storage and grant read permission to the URI.
- startActivityAsUser(
- new Intent(this, AppClipsTrampolineActivity.class)
- .putExtra(EXTRA_USE_WP_USER, /* value= */ true)
- .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), mainUser);
- }
-
private void setErrorResultAndFinish(int errorCode) {
setResult(RESULT_OK,
new Intent().putExtra(EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE, errorCode));
@@ -241,7 +226,7 @@
int callingPackageUid = 0;
try {
callingPackageUid = mPackageManager.getApplicationInfoAsUser(callingPackageName,
- APPLICATION_INFO_FLAGS, mNotesAppUser.getIdentifier()).uid;
+ APPLICATION_INFO_FLAGS, mUserHandle.getIdentifier()).uid;
} catch (NameNotFoundException e) {
Log.d(TAG, "Couldn't find notes app UID " + e);
}
@@ -281,7 +266,7 @@
mKillAppClipsBroadcastIntent = null;
// Expand the note bubble before returning the result.
- mNoteTaskController.showNoteTaskAsUser(NoteTaskEntryPoint.APP_CLIPS, mNotesAppUser);
+ mNoteTaskController.showNoteTaskAsUser(NoteTaskEntryPoint.APP_CLIPS, mUserHandle);
setResult(RESULT_OK, convertedData);
finish();
}
@@ -298,11 +283,18 @@
appClipsResultReceiver.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
- ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
+ ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
parcel.recycle();
return resultReceiver;
}
+ private ServiceConnector<IAppClipsService> createServiceConnector(
+ @Application Context context) {
+ return new ServiceConnector.Impl<>(context, new Intent(context, AppClipsService.class),
+ Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY | Context.BIND_NOT_VISIBLE,
+ UserHandle.USER_SYSTEM, IAppClipsService.Stub::asInterface);
+ }
+
/** This is a test only API for mocking response from {@link AppClipsActivity}. */
@VisibleForTesting
public ResultReceiver getResultReceiverForTest() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 047fea1..7f4c2a6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -125,6 +125,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
@@ -598,6 +599,7 @@
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final KeyguardInteractor mKeyguardInteractor;
+ private final KeyguardViewConfigurator mKeyguardViewConfigurator;
private final @Nullable MultiShadeInteractor mMultiShadeInteractor;
private final CoroutineDispatcher mMainDispatcher;
private boolean mIsAnyMultiShadeExpanded;
@@ -740,6 +742,7 @@
KeyguardLongPressViewModel keyguardLongPressViewModel,
KeyguardInteractor keyguardInteractor,
ActivityStarter activityStarter,
+ KeyguardViewConfigurator keyguardViewConfigurator,
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) {
mInteractionJankMonitor = interactionJankMonitor;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -762,6 +765,7 @@
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mKeyguardInteractor = keyguardInteractor;
+ mKeyguardViewConfigurator = keyguardViewConfigurator;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
@@ -1319,7 +1323,6 @@
mKeyguardBottomArea.initFrom(oldBottomArea);
mView.addView(mKeyguardBottomArea, index);
initBottomArea();
- mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
@@ -1361,6 +1364,9 @@
mKeyguardIndicationController.showTransientIndication(stringResourceId),
mVibratorHelper,
mActivityStarter);
+
+ // Rebind (for now), as a new bottom area and indication area may have been created
+ mKeyguardViewConfigurator.bindIndicationArea(mKeyguardBottomArea);
}
@VisibleForTesting
@@ -1398,7 +1404,6 @@
private void setKeyguardBottomArea(KeyguardBottomAreaView keyguardBottomArea) {
mKeyguardBottomArea = keyguardBottomArea;
- mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
}
void setOpenCloseListener(OpenCloseListener openCloseListener) {
@@ -3023,12 +3028,6 @@
mKeyguardStatusViewController.setStatusAccessibilityImportance(mode);
}
- //TODO(b/254875405): this should be removed.
- @Override
- public KeyguardBottomAreaView getKeyguardBottomAreaView() {
- return mKeyguardBottomArea;
- }
-
@Override
public void applyLaunchAnimationProgress(float linearProgress) {
boolean hideIcons = LaunchAnimator.getProgress(ActivityLaunchAnimator.TIMINGS,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 0c800d4..8105a145 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -103,7 +103,7 @@
private final KeyguardViewMediator mKeyguardViewMediator;
private final KeyguardBypassController mKeyguardBypassController;
private final AuthController mAuthController;
- private ViewGroup mNotificationShadeView;
+ private ViewGroup mWindowRootView;
private LayoutParams mLp;
private boolean mHasTopUi;
private boolean mHasTopUiChanged;
@@ -262,7 +262,7 @@
mLp.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- mWindowManager.addView(mNotificationShadeView, mLp);
+ mWindowManager.addView(mWindowRootView, mLp);
mLpChanged.copyFrom(mLp);
onThemeChanged();
@@ -274,13 +274,13 @@
}
@Override
- public void setNotificationShadeView(ViewGroup view) {
- mNotificationShadeView = view;
+ public void setWindowRootView(ViewGroup view) {
+ mWindowRootView = view;
}
@Override
- public ViewGroup getNotificationShadeView() {
- return mNotificationShadeView;
+ public ViewGroup getWindowRootView() {
+ return mWindowRootView;
}
@Override
@@ -289,7 +289,7 @@
}
private void setKeyguardDark(boolean dark) {
- int vis = mNotificationShadeView.getSystemUiVisibility();
+ int vis = mWindowRootView.getSystemUiVisibility();
if (dark) {
vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
vis = vis | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
@@ -297,7 +297,7 @@
vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
- mNotificationShadeView.setSystemUiVisibility(vis);
+ mWindowRootView.setSystemUiVisibility(vis);
}
private void applyKeyguardFlags(NotificationShadeWindowState state) {
@@ -413,11 +413,11 @@
visible = true;
mLogger.d("Visibility forced to be true");
}
- if (mNotificationShadeView != null) {
+ if (mWindowRootView != null) {
if (visible) {
- mNotificationShadeView.setVisibility(View.VISIBLE);
+ mWindowRootView.setVisibility(View.VISIBLE);
} else {
- mNotificationShadeView.setVisibility(View.INVISIBLE);
+ mWindowRootView.setVisibility(View.INVISIBLE);
}
}
}
@@ -439,10 +439,10 @@
private void applyFitsSystemWindows(NotificationShadeWindowState state) {
boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
- if (mNotificationShadeView != null
- && mNotificationShadeView.getFitsSystemWindows() != fitsSystemWindows) {
- mNotificationShadeView.setFitsSystemWindows(fitsSystemWindows);
- mNotificationShadeView.requestApplyInsets();
+ if (mWindowRootView != null
+ && mWindowRootView.getFitsSystemWindows() != fitsSystemWindows) {
+ mWindowRootView.setFitsSystemWindows(fitsSystemWindows);
+ mWindowRootView.requestApplyInsets();
}
}
@@ -482,7 +482,7 @@
if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
mLogger.logApplyingWindowLayoutParams(mLp);
Trace.beginSection("updateViewLayout");
- mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
+ mWindowManager.updateViewLayout(mWindowRootView, mLp);
Trace.endSection();
}
}
@@ -608,7 +608,7 @@
try {
final IWindowSession session = WindowManagerGlobal.getWindowSession();
session.updateTapExcludeRegion(
- IWindow.Stub.asInterface(getNotificationShadeView().getWindowToken()),
+ IWindow.Stub.asInterface(getWindowRootView().getWindowToken()),
region);
} catch (RemoteException e) {
Log.e(TAG, "could not update the tap exclusion region:" + e);
@@ -847,8 +847,8 @@
pw.println(" mKeyguardPreferredRefreshRate=" + mKeyguardPreferredRefreshRate);
pw.println(" mDeferWindowLayoutParams=" + mDeferWindowLayoutParams);
pw.println(mCurrentState);
- if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
- mNotificationShadeView.getViewRootImpl().dump(" ", pw);
+ if (mWindowRootView != null && mWindowRootView.getViewRootImpl() != null) {
+ mWindowRootView.getViewRootImpl().dump(" ", pw);
}
new DumpsysTableLogger(
TAG,
@@ -864,7 +864,7 @@
@Override
public void onThemeChanged() {
- if (mNotificationShadeView == null) {
+ if (mWindowRootView == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
index d75190e..c9122c7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
@@ -59,11 +59,14 @@
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import com.android.systemui.R;
import com.android.systemui.compose.ComposeFacade;
+import com.android.systemui.scene.ui.view.WindowRootView;
/**
- * Combined keyguard and notification panel view. Also holding backdrop and scrims.
+ * Combined keyguard and notification panel view. Also holding backdrop and scrims. This view can
+ * serve as the root view of the main SysUI window, but because other views can also serve that
+ * purpose, users of this class cannot assume it is the root.
*/
-public class NotificationShadeWindowView extends FrameLayout {
+public class NotificationShadeWindowView extends WindowRootView {
public static final String TAG = "NotificationShadeWindowView";
private int mRightInset = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 2f7644e..f4485c9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
+import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
@@ -45,12 +46,14 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.log.BouncerLogger;
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor;
import com.android.systemui.multishade.domain.interactor.MultiShadeMotionEventInteractor;
import com.android.systemui.multishade.ui.view.MultiShadeView;
@@ -149,12 +152,15 @@
PulsingGestureListener pulsingGestureListener,
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
KeyguardTransitionInteractor keyguardTransitionInteractor,
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
FeatureFlags featureFlags,
Provider<MultiShadeInteractor> multiShadeInteractorProvider,
SystemClock clock,
- Provider<MultiShadeMotionEventInteractor> multiShadeMotionEventInteractorProvider) {
+ Provider<MultiShadeMotionEventInteractor> multiShadeMotionEventInteractorProvider,
+ BouncerMessageInteractor bouncerMessageInteractor,
+ BouncerLogger bouncerLogger) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
@@ -183,7 +189,11 @@
mView.findViewById(R.id.keyguard_bouncer_container),
keyguardBouncerViewModel,
primaryBouncerToGoneTransitionViewModel,
- keyguardBouncerComponentFactory);
+ keyguardBouncerComponentFactory,
+ messageAreaControllerFactory,
+ bouncerMessageInteractor,
+ bouncerLogger,
+ featureFlags);
collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
mLockscreenToDreamingTransition);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index b7551cf..1752ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -31,7 +31,10 @@
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
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -61,17 +64,33 @@
@Provides
@SysUISingleton
+ fun providesWindowRootView(
+ layoutInflater: LayoutInflater,
+ featureFlags: FeatureFlags,
+ ): WindowRootView {
+ return if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ layoutInflater.inflate(R.layout.scene_window_root, null)
+ } else {
+ layoutInflater.inflate(R.layout.super_notification_shade, null)
+ }
+ as WindowRootView?
+ ?: throw IllegalStateException("Window root view could not be properly inflated")
+ }
+
+ @Provides
+ @SysUISingleton
// TODO(b/277762009): Do something similar to
// {@link StatusBarWindowModule.InternalWindowView} so that only
// {@link NotificationShadeWindowViewController} can inject this view.
fun providesNotificationShadeWindowView(
- layoutInflater: LayoutInflater,
+ root: WindowRootView,
+ featureFlags: FeatureFlags,
): NotificationShadeWindowView {
- return layoutInflater.inflate(R.layout.super_notification_shade, /* root= */ null)
- as NotificationShadeWindowView?
- ?: throw IllegalStateException(
- "R.layout.super_notification_shade could not be properly inflated"
- )
+ if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ return root.findViewById(R.id.legacy_window_root)
+ }
+ return root as NotificationShadeWindowView?
+ ?: throw IllegalStateException("root view not a NotificationShadeWindowView")
}
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@@ -100,6 +119,14 @@
return notificationShadeWindowView.findViewById(R.id.light_reveal_scrim)
}
+ @Provides
+ @SysUISingleton
+ fun providesKeyguardRootView(
+ notificationShadeWindowView: NotificationShadeWindowView,
+ ): KeyguardRootView {
+ return notificationShadeWindowView.findViewById(R.id.keyguard_root_view)
+ }
+
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index f75047c..203355e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -21,7 +21,6 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController
-import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
import com.android.systemui.statusbar.phone.KeyguardStatusBarView
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController
import java.util.function.Consumer
@@ -120,13 +119,6 @@
/** Returns the StatusBarState. */
val barState: Int
- /**
- * Returns the bottom part of the keyguard, which contains quick affordances.
- *
- * TODO(b/275550429): this should be removed.
- */
- val keyguardBottomAreaView: KeyguardBottomAreaView?
-
/** Returns the NSSL controller. */
val notificationStackScrollLayoutController: NotificationStackScrollLayoutController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 12420ff..f409f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -94,6 +94,7 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.FalsingManager;
@@ -147,6 +148,7 @@
private final AuthController mAuthController;
private final KeyguardLogger mKeyguardLogger;
private final UserTracker mUserTracker;
+ private final BouncerMessageInteractor mBouncerMessageInteractor;
private ViewGroup mIndicationArea;
private KeyguardIndicationTextView mTopIndicationView;
private KeyguardIndicationTextView mLockScreenIndicationView;
@@ -253,7 +255,8 @@
KeyguardLogger keyguardLogger,
AlternateBouncerInteractor alternateBouncerInteractor,
AlarmManager alarmManager,
- UserTracker userTracker
+ UserTracker userTracker,
+ BouncerMessageInteractor bouncerMessageInteractor
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -278,7 +281,7 @@
mScreenLifecycle.addObserver(mScreenObserver);
mAlternateBouncerInteractor = alternateBouncerInteractor;
mUserTracker = userTracker;
-
+ mBouncerMessageInteractor = bouncerMessageInteractor;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
int[] msgIds = context.getResources().getIntArray(
@@ -1151,6 +1154,11 @@
msgId,
helpString);
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ if (biometricSourceType == FINGERPRINT && !fpAuthFailed) {
+ mBouncerMessageInteractor.setFingerprintAcquisitionMessage(helpString);
+ } else if (faceAuthSoftError) {
+ mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString);
+ }
mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
@@ -1206,6 +1214,8 @@
if (biometricSourceType == FACE) {
mFaceAcquiredMessageDeferral.reset();
}
+ mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
+ mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
@@ -1226,6 +1236,8 @@
} else if (biometricSourceType == FINGERPRINT) {
onFingerprintAuthError(msgId, errString);
}
+ mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
+ mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
private void onFaceAuthError(int msgId, String errString) {
@@ -1310,6 +1322,8 @@
showActionToUnlock();
}
}
+ mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
+ mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 2ca0b00..47a4641 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -60,11 +60,11 @@
default void attach() {}
/** Sets the notification shade view. */
- default void setNotificationShadeView(ViewGroup view) {}
+ default void setWindowRootView(ViewGroup view) {}
/** Gets the notification shade view. */
@Nullable
- default ViewGroup getNotificationShadeView() {
+ default ViewGroup getWindowRootView() {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index b81cb2b..cdc7cee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -197,7 +197,6 @@
*/
private Set<Integer> mDebugTextUsedYPositions;
private final boolean mDebugRemoveAnimation;
- private final boolean mSimplifiedAppearFraction;
private final boolean mSensitiveRevealAnimEndabled;
private boolean mAnimatedInsets;
@@ -621,7 +620,6 @@
FeatureFlags featureFlags = Dependency.get(FeatureFlags.class);
mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
- mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
@@ -1638,14 +1636,6 @@
return mAmbientState.getTrackedHeadsUpRow() != null;
}
- // TODO(b/246353296): remove it when Flags.SIMPLIFIED_APPEAR_FRACTION is removed
- public float calculateAppearFractionOld(float height) {
- float appearEndPosition = getAppearEndPosition();
- float appearStartPosition = getAppearStartPosition();
- return (height - appearStartPosition)
- / (appearEndPosition - appearStartPosition);
- }
-
/**
* @param height the height of the panel
* @return Fraction of the appear animation that has been performed. Normally follows expansion
@@ -1653,33 +1643,24 @@
* when HUN is swiped up.
*/
@FloatRange(from = -1.0, to = 1.0)
- public float simplifiedAppearFraction(float height) {
+ public float calculateAppearFraction(float height) {
if (isHeadsUpTransition()) {
// HUN is a special case because fraction can go negative if swiping up. And for now
// it must go negative as other pieces responsible for proper translation up assume
// negative value for HUN going up.
// This can't use expansion fraction as that goes only from 0 to 1. Also when
// appear fraction for HUN is 0, expansion fraction will be already around 0.2-0.3
- // and that makes translation jump immediately. Let's use old implementation for now and
- // see if we can figure out something better
- return MathUtils.constrain(calculateAppearFractionOld(height), -1, 1);
+ // and that makes translation jump immediately.
+ float appearEndPosition = getAppearEndPosition();
+ float appearStartPosition = getAppearStartPosition();
+ float hunAppearFraction = (height - appearStartPosition)
+ / (appearEndPosition - appearStartPosition);
+ return MathUtils.constrain(hunAppearFraction, -1, 1);
} else {
return mAmbientState.getExpansionFraction();
}
}
- public float calculateAppearFraction(float height) {
- if (mSimplifiedAppearFraction) {
- return simplifiedAppearFraction(height);
- } else if (mShouldUseSplitNotificationShade) {
- // for split shade we want to always use the new way of calculating appear fraction
- // because without it heads-up experience is very broken and it's less risky change
- return simplifiedAppearFraction(height);
- } else {
- return calculateAppearFractionOld(height);
- }
- }
-
public float getStackTranslation() {
return mStackTranslation;
}
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 86bf7cb..226df76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -28,9 +28,9 @@
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
import android.view.View;
-import android.view.ViewGroup;
import android.window.RemoteTransition;
import android.window.SplashScreen;
@@ -39,7 +39,6 @@
import androidx.lifecycle.LifecycleOwner;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -51,7 +50,6 @@
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
-import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.util.Compile;
@@ -69,14 +67,11 @@
String TAG = "CentralSurfaces";
boolean DEBUG = false;
boolean SPEW = false;
- boolean DUMPTRUCK = true; // extra dumpsys info
boolean DEBUG_GESTURES = false;
boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
boolean DEBUG_CAMERA_LIFT = false;
boolean DEBUG_WINDOW_STATE = false;
boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG;
- // additional instrumentation for testing purposes; intended to be left on during development
- boolean CHATTY = DEBUG;
boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
String ACTION_FAKE_ARTWORK = "fake_artwork";
int FADE_KEYGUARD_START_DELAY = 100;
@@ -239,8 +234,6 @@
void onKeyguardViewManagerStatesUpdated();
- ViewGroup getNotificationScrollLayout();
-
boolean isPulsing();
boolean isOccluded();
@@ -266,8 +259,21 @@
boolean isPanelExpanded();
+ /**
+ * Used to dispatch initial touch events before crossing the threshold to pull down the
+ * notification shade. After that, since the launcher window is set to slippery, input
+ * frameworks take care of routing the events to the notification shade.
+ */
void onInputFocusTransfer(boolean start, boolean cancel, float velocity);
+ /**
+ * Dispatches status bar motion event to the notification shade. This is different from
+ * {@link #onInputFocusTransfer(boolean, boolean, float)} as it doesn't rely on setting the
+ * launcher window slippery to allow the frameworks to route those events after passing the
+ * initial threshold.
+ */
+ default void onStatusBarTrackpadEvent(MotionEvent event) {}
+
void animateCollapseQuickSettings();
/** */
@@ -289,8 +295,6 @@
@Override
void dump(PrintWriter pwOriginal, String[] args);
- void createAndAddWindows(@Nullable RegisterStatusBarResult result);
-
float getDisplayWidth();
float getDisplayHeight();
@@ -340,8 +344,6 @@
void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
Runnable cancelAction);
- LightRevealScrim getLightRevealScrim();
-
// TODO: Figure out way to remove these.
NavigationBarView getNavigationBarView();
@@ -455,8 +457,6 @@
void extendDozePulse();
- boolean shouldDelayWakeUpAnimation();
-
public static class KeyboardShortcutsMessage {
final int mDeviceId;
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 0402d4f..cab95c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -91,6 +91,7 @@
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
@@ -428,6 +429,7 @@
public void togglePanel() {
mCommandQueueCallbacks.togglePanel();
}
+
/**
* The {@link StatusBarState} of the status bar.
*/
@@ -498,7 +500,6 @@
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final PluginDependencyProvider mPluginDependencyProvider;
- private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ExtensionController mExtensionController;
private final UserInfoControllerImpl mUserInfoControllerImpl;
private final DemoModeController mDemoModeController;
@@ -785,7 +786,6 @@
InitController initController,
@Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler,
PluginDependencyProvider pluginDependencyProvider,
- KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
PhoneStatusBarPolicy phoneStatusBarPolicy,
@@ -882,7 +882,6 @@
mKeyguardViewMediatorCallback = viewMediatorCallback;
mInitController = initController;
mPluginDependencyProvider = pluginDependencyProvider;
- mKeyguardDismissUtil = keyguardDismissUtil;
mExtensionController = extensionController;
mUserInfoControllerImpl = userInfoControllerImpl;
mIconPolicy = phoneStatusBarPolicy;
@@ -1658,12 +1657,13 @@
CollapsedStatusBarFragment.class,
mCentralSurfacesComponent::createCollapsedStatusBarFragment);
+ ViewGroup windowRootView = mCentralSurfacesComponent.getWindowRootView();
mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView();
mNotificationShadeWindowViewController = mCentralSurfacesComponent
.getNotificationShadeWindowViewController();
// TODO(b/277762009): Inject [NotificationShadeWindowView] directly into the controller.
// (Right now, there's a circular dependency.)
- mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
+ mNotificationShadeWindowController.setWindowRootView(windowRootView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
NotificationPanelViewController npvc =
mCentralSurfacesComponent.getNotificationPanelViewController();
@@ -1739,7 +1739,6 @@
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
- mKeyguardDismissUtil.setDismissHandler(this::executeWhenUnlocked);
Trace.endSection();
}
@@ -1826,11 +1825,6 @@
}
@Override
- public ViewGroup getNotificationScrollLayout() {
- return mStackScroller;
- }
-
- @Override
public boolean isPulsing() {
return mDozeServiceHost.isPulsing();
}
@@ -1991,6 +1985,11 @@
}
@Override
+ public void onStatusBarTrackpadEvent(MotionEvent event) {
+ mCentralSurfacesComponent.getNotificationPanelViewController().handleExternalTouch(event);
+ }
+
+ @Override
public void animateCollapseQuickSettings() {
if (mState == StatusBarState.SHADE) {
mShadeSurface.collapse(
@@ -2249,8 +2248,7 @@
+ CameraIntents.getOverrideCameraPackage(mContext));
}
- @Override
- public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
+ private void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
makeStatusBarView(result);
mNotificationShadeWindowController.attach();
mStatusBarWindowController.attach();
@@ -2358,15 +2356,6 @@
mNotificationsController.resetUserExpandedStates();
}
- private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen,
- boolean afterKeyguardGone) {
- if (mKeyguardStateController.isShowing() && requiresShadeOpen) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
- }
- mActivityStarter.dismissKeyguardThenExecute(action, null /* cancelAction */,
- afterKeyguardGone /* afterKeyguardGone */);
- }
-
/**
* Notify the shade controller that the current user changed
*
@@ -2836,7 +2825,11 @@
}
private void updateDozingState() {
- Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0);
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, "Dozing", 0);
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, "Dozing", String.valueOf(mDozing),
+ 0);
+ }
Trace.beginSection("CentralSurfaces#updateDozingState");
boolean keyguardVisible = mKeyguardStateController.isVisible();
@@ -3036,11 +3029,6 @@
}
}
- @Override
- public LightRevealScrim getLightRevealScrim() {
- return mLightRevealScrim;
- }
-
// TODO: Figure out way to remove these.
@Override
public NavigationBarView getNavigationBarView() {
@@ -3190,6 +3178,10 @@
@Override
public void onStartedWakingUp() {
+ // Between onStartedWakingUp() and onFinishedWakingUp(), the system is changing the
+ // display power mode. To avoid jank, animations should NOT run during these power
+ // mode transitions, which means that whenever possible, animations should
+ // start running during the onFinishedWakingUp() callback instead of this callback.
String tag = "CentralSurfaces#onStartedWakingUp";
DejankUtils.startDetectingBlockingIpcs(tag);
mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
@@ -3234,6 +3226,14 @@
updateVisibleToUser();
updateIsKeyguard();
+ });
+ DejankUtils.stopDetectingBlockingIpcs(tag);
+ }
+
+ @Override
+ public void onFinishedWakingUp() {
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ // stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation.
mDozeServiceHost.stopDozing();
// This is intentionally below the stopDozing call above, since it avoids that we're
// unnecessarily animating the wakeUp transition. Animations should only be enabled
@@ -3247,13 +3247,7 @@
if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) {
mShadeController.makeExpandedInvisible();
}
-
});
- DejankUtils.stopDetectingBlockingIpcs(tag);
- }
-
- @Override
- public void onFinishedWakingUp() {
mWakeUpCoordinator.setFullyAwake(true);
mWakeUpCoordinator.setWakingUp(false, false);
if (mKeyguardStateController.isOccluded()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index 27b68f2..1c90c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -16,48 +16,41 @@
package com.android.systemui.statusbar.phone;
-import android.util.Log;
-
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
/**
- * Executes actions that require the screen to be unlocked. Delegates the actual handling to an
- * implementation passed via {@link #setDismissHandler}.
+ * Executes actions that require the screen to be unlocked.
*/
@SysUISingleton
public class KeyguardDismissUtil implements KeyguardDismissHandler {
- private static final String TAG = "KeyguardDismissUtil";
+ private final KeyguardStateController mKeyguardStateController;
- private volatile KeyguardDismissHandler mDismissHandler;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+
+ private final ActivityStarter mActivityStarter;
@Inject
- public KeyguardDismissUtil() {
+ public KeyguardDismissUtil(KeyguardStateController keyguardStateController,
+ SysuiStatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter) {
+ mKeyguardStateController = keyguardStateController;
+ mStatusBarStateController = statusBarStateController;
+ mActivityStarter = activityStarter;
}
- /** Sets the actual {@link KeyguardDismissHandler} implementation. */
- public void setDismissHandler(KeyguardDismissHandler dismissHandler) {
- mDismissHandler = dismissHandler;
- }
-
- /**
- * Executes an action that requires the screen to be unlocked.
- *
- * <p>Must be called after {@link #setDismissHandler}.
- *
- * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
- */
@Override
public void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen,
boolean afterKeyguardGone) {
- KeyguardDismissHandler dismissHandler = mDismissHandler;
- if (dismissHandler == null) {
- Log.wtf(TAG, "KeyguardDismissHandler not set.");
- action.onDismiss();
- return;
+ if (mKeyguardStateController.isShowing() && requiresShadeOpen) {
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
}
- dismissHandler.executeWhenUnlocked(action, requiresShadeOpen, afterKeyguardGone);
+ mActivityStarter.dismissKeyguardThenExecute(action, null /* cancelAction */,
+ afterKeyguardGone /* afterKeyguardGone */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 1bf63be..a34cc96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1312,7 +1312,7 @@
@Override
public ViewRootImpl getViewRootImpl() {
- ViewGroup viewGroup = mNotificationShadeWindowController.getNotificationShadeView();
+ ViewGroup viewGroup = mNotificationShadeWindowController.getWindowRootView();
if (viewGroup != null) {
return viewGroup.getViewRootImpl();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index dfaee4c..5624e28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -40,7 +40,6 @@
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -86,7 +85,6 @@
private final HeadsUpManagerPhone mHeadsUpManager;
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
- private final KeyguardIndicationController mKeyguardIndicationController;
private final CentralSurfaces mCentralSurfaces;
private final LockscreenShadeTransitionController mShadeTransitionController;
private final CommandQueue mCommandQueue;
@@ -115,7 +113,6 @@
NotificationShadeWindowController notificationShadeWindowController,
DynamicPrivacyController dynamicPrivacyController,
KeyguardStateController keyguardStateController,
- KeyguardIndicationController keyguardIndicationController,
CentralSurfaces centralSurfaces,
LockscreenShadeTransitionController shadeTransitionController,
CommandQueue commandQueue,
@@ -137,7 +134,6 @@
mQsController = quickSettingsController;
mHeadsUpManager = headsUp;
mDynamicPrivacyController = dynamicPrivacyController;
- mKeyguardIndicationController = keyguardIndicationController;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mCentralSurfaces = centralSurfaces;
mShadeTransitionController = shadeTransitionController;
@@ -173,7 +169,6 @@
mNotificationPanel.getShadeNotificationPresenter().createRemoteInputDelegate());
initController.addPostInitTask(() -> {
- mKeyguardIndicationController.init();
mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied);
mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse);
notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
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 273e783..158f961 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
@@ -20,6 +20,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.scene.ui.view.WindowRootView;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
@@ -80,8 +81,11 @@
@Scope
@interface CentralSurfacesScope {}
+ /** Creates the root view of the main SysUI window}. */
+ WindowRootView getWindowRootView();
+
/**
- * Creates a {@link NotificationShadeWindowView}.
+ * Creates or returns a {@link NotificationShadeWindowView}.
*/
NotificationShadeWindowView getNotificationShadeWindowView();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 080be6d..12da17f 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -192,12 +192,6 @@
android:excludeFromRecents="true" />
<activity
- android:name="com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity"
- android:exported="false"
- android:permission="com.android.systemui.permission.SELF"
- android:excludeFromRecents="true" />
-
- <activity
android:name="com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity"
android:exported="false"
android:permission="com.android.systemui.permission.SELF"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 3f1560b..8c71392 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -53,6 +53,7 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
@@ -62,6 +63,7 @@
import org.mockito.junit.MockitoJUnit
import java.util.TimeZone
import java.util.concurrent.Executor
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@@ -117,6 +119,7 @@
commandQueue = commandQueue,
featureFlags = featureFlags,
bouncerRepository = bouncerRepository,
+ configurationRepository = FakeConfigurationRepository(),
),
KeyguardTransitionInteractor(repository = transitionRepository),
broadcastDispatcher,
@@ -155,9 +158,8 @@
@Test
fun themeChanged_verifyClockPaletteUpdated() = runBlocking(IMMEDIATE) {
- // TODO(b/266103601): delete this test and add more coverage for updateColors()
- // verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
- // verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
+ verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+ verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
verify(configurationController).addCallback(capture(captor))
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 254f953..8dc1e8f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -189,6 +190,7 @@
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -198,6 +200,7 @@
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -212,6 +215,7 @@
// only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -223,6 +227,7 @@
// only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index d2e5a45..e1ba488 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -67,6 +67,7 @@
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -216,7 +217,8 @@
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
mTelephonyManager, mViewMediatorCallback, mAudioManager,
- mock(KeyguardFaceAuthInteractor.class));
+ mock(KeyguardFaceAuthInteractor.class),
+ mock(BouncerMessageInteractor.class));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 456702b..bdf6bee 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -18,6 +18,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
+import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -42,15 +43,12 @@
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -91,10 +89,9 @@
protected @Mock ConfigurationController mConfigurationController;
protected @Mock VibratorHelper mVibrator;
protected @Mock AuthRippleController mAuthRippleController;
- protected @Mock FeatureFlags mFeatureFlags;
protected @Mock KeyguardTransitionRepository mTransitionRepository;
- protected @Mock CommandQueue mCommandQueue;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
+ protected FakeFeatureFlags mFeatureFlags;
protected LockIconViewController mUnderTest;
@@ -144,6 +141,8 @@
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mFeatureFlags = new FakeFeatureFlags();
+ mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mUnderTest = new LockIconViewController(
mLockIconView,
mStatusBarStateController,
@@ -160,12 +159,7 @@
mAuthRippleController,
mResources,
new KeyguardTransitionInteractor(mTransitionRepository),
- new KeyguardInteractor(
- new FakeKeyguardRepository(),
- mCommandQueue,
- mFeatureFlags,
- new FakeKeyguardBouncerRepository()
- ),
+ KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
mFeatureFlags
);
}
@@ -226,7 +220,7 @@
}
protected void init(boolean useMigrationFlag) {
- when(mFeatureFlags.isEnabled(DOZING_MIGRATION_1)).thenReturn(useMigrationFlag);
+ mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag);
mUnderTest.init();
verify(mLockIconView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
index 665246b..62a176c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
@@ -73,9 +73,9 @@
@Test
public void testShowSettingsPanel() {
- mMagnificationSettingsController.showMagnificationSettings();
+ mMagnificationSettingsController.toggleSettingsPanelVisibility();
- verify(mWindowMagnificationSettings).showSettingPanel();
+ verify(mWindowMagnificationSettings).toggleSettingsPanelVisibility();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 9c36af3..31c09b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility;
+import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -96,6 +97,7 @@
import com.google.common.util.concurrent.AtomicDouble;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -147,8 +149,15 @@
private View.OnTouchListener mTouchListener;
private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+ /**
+ * return whether window magnification is supported for current test context.
+ */
+ private boolean isWindowModeSupported() {
+ return getContext().getPackageManager().hasSystemFeature(FEATURE_WINDOW_MAGNIFICATION);
+ }
+
@Before
- public void setUp() throws RemoteException {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = Mockito.spy(getContext());
mHandler = new FakeHandler(TestableLooper.get(this).getLooper());
@@ -202,6 +211,9 @@
return null;
}).when(mSpyView).setOnTouchListener(
any(View.OnTouchListener.class));
+
+ // skip test if window magnification is not supported to prevent fail results. (b/279820875)
+ Assume.assumeTrue(isWindowModeSupported());
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index ce96708..df08dec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -37,6 +37,7 @@
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -49,6 +50,7 @@
import android.widget.CompoundButton;
import android.widget.LinearLayout;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -65,7 +67,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class WindowMagnificationSettingsTest extends SysuiTestCase {
private static final int MAGNIFICATION_SIZE_SMALL = 1;
@@ -275,6 +277,39 @@
}
@Test
+ public void onScreenSizeChanged_resetPositionToRightBottomCorner() {
+ setupMagnificationCapabilityAndMode(
+ /* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
+ /* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ mWindowMagnificationSettings.showSettingPanel();
+
+ // move the panel to the center of draggable window bounds
+ mWindowMagnificationSettings.mParams.x =
+ mWindowMagnificationSettings.mDraggableWindowBounds.centerX();
+ mWindowMagnificationSettings.mParams.y =
+ mWindowMagnificationSettings.mDraggableWindowBounds.centerY();
+ mWindowMagnificationSettings.updateButtonViewLayoutIfNeeded();
+
+ final Rect testWindowBounds = new Rect(
+ mWindowManager.getCurrentWindowMetrics().getBounds());
+ testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
+ testWindowBounds.right + 200, testWindowBounds.bottom + 50);
+ mWindowManager.setWindowBounds(testWindowBounds);
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mWindowMagnificationSettings.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+ });
+
+ // the panel position should be reset to the bottom-right corner
+ assertEquals(
+ mWindowMagnificationSettings.mParams.x,
+ mWindowMagnificationSettings.mDraggableWindowBounds.right);
+ assertEquals(
+ mWindowMagnificationSettings.mParams.y,
+ mWindowMagnificationSettings.mDraggableWindowBounds.bottom);
+ }
+
+ @Test
public void showSettingsPanel_observerRegistered() {
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 38ecec0..db58074 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -110,7 +110,7 @@
mWindowMagnification.mMagnificationSettingsControllerCallback
.onSettingsPanelVisibilityChanged(TEST_DISPLAY, /* shown= */ true);
return null;
- }).when(mMagnificationSettingsController).showMagnificationSettings();
+ }).when(mMagnificationSettingsController).toggleSettingsPanelVisibility();
doAnswer(invocation -> {
mWindowMagnification.mMagnificationSettingsControllerCallback
.onSettingsPanelVisibilityChanged(TEST_DISPLAY, /* shown= */ false);
@@ -198,7 +198,7 @@
mWindowMagnification.mWindowMagnifierCallback.onClickSettingsButton(TEST_DISPLAY);
waitForIdleSync();
- verify(mMagnificationSettingsController).showMagnificationSettings();
+ verify(mMagnificationSettingsController).toggleSettingsPanelVisibility();
verify(mA11yLogger).log(
eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 1990c8f..3a93e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.authentication.domain.interactor
+import android.app.admin.DevicePolicyManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository
@@ -48,7 +49,7 @@
fun authMethod() =
testScope.runTest {
val authMethod by collectLastValue(underTest.authenticationMethod)
- assertThat(authMethod).isEqualTo(AuthenticationMethodModel.PIN(1234))
+ assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234))
underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password"))
@@ -147,7 +148,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
@@ -160,7 +161,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
@@ -169,6 +170,51 @@
}
@Test
+ fun authenticate_withEmptyPin_returnsFalseAndDoesNotUnlockDevice() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf())).isFalse()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(1)
+ }
+
+ @Test
+ fun authenticate_withCorrectMaxLengthPin_returnsTrueAndUnlocksDevice() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999))
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
+ assertThat(isUnlocked).isTrue()
+ assertThat(failedAttemptCount).isEqualTo(0)
+ }
+
+ @Test
+ fun authenticate_withCorrectTooLongPin_returnsFalseAndDoesNotUnlockDevice() =
+ testScope.runTest {
+ // Max pin length is 16 digits. To avoid issues with overflows, this test ensures
+ // that all pins > 16 decimal digits are rejected.
+
+ // If the policy changes, there is work to do in SysUI.
+ assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
+
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999))
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(1)
+ }
+
+ @Test
fun authenticate_withCorrectPassword_returnsTrueAndUnlocksDevice() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 374c28d6..6a63c32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -69,7 +69,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -167,7 +167,7 @@
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
runCurrent()
@@ -211,7 +211,7 @@
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(throttling).isNull()
assertThat(message).isEqualTo("")
assertThat(isUnlocked).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 1642410..b53e034 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -55,7 +55,7 @@
@Test
fun animateFailure() =
testScope.runTest {
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
val animateFailure by collectLastValue(underTest.animateFailure)
assertThat(animateFailure).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index e8c946c..c607496 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -97,7 +97,7 @@
testScope.runTest {
val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(message?.isUpdateAnimated).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -120,7 +120,7 @@
}
)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(isInputEnabled).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -137,7 +137,7 @@
fun throttlingDialogMessage() =
testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
repeat(BouncerInteractor.THROTTLE_EVERY) {
// Wrong PIN.
@@ -154,7 +154,7 @@
return listOf(
AuthenticationMethodModel.None,
AuthenticationMethodModel.Swipe,
- AuthenticationMethodModel.PIN(1234),
+ AuthenticationMethodModel.Pin(1234),
AuthenticationMethodModel.Password("password"),
AuthenticationMethodModel.Pattern(
listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 3bdaf05..7b6bb37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -25,12 +25,12 @@
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -85,8 +85,8 @@
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -95,7 +95,7 @@
underTest.onShown()
assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN)
- assertThat(pinLengths).isEqualTo(0 to 0)
+ assertThat(entries).hasSize(0)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -106,8 +106,8 @@
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -117,7 +117,8 @@
underTest.onPinButtonClicked(1)
assertThat(message?.text).isEmpty()
- assertThat(pinLengths).isEqualTo(0 to 1)
+ assertThat(entries).hasSize(1)
+ assertThat(entries?.map { it.input }).containsExactly(1)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -128,32 +129,59 @@
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
- assertThat(pinLengths).isEqualTo(0 to 1)
+ assertThat(entries).hasSize(1)
underTest.onBackspaceButtonClicked()
assertThat(message?.text).isEmpty()
- assertThat(pinLengths).isEqualTo(1 to 0)
+ assertThat(entries).hasSize(0)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
+ fun onPinEdit() =
+ testScope.runTest {
+ val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
+ val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val message by collectLastValue(bouncerViewModel.message)
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ authenticationInteractor.lockDevice()
+ sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+
+ underTest.onPinButtonClicked(1)
+ underTest.onPinButtonClicked(2)
+ underTest.onPinButtonClicked(3)
+ underTest.onBackspaceButtonClicked()
+ underTest.onBackspaceButtonClicked()
+ underTest.onPinButtonClicked(4)
+ underTest.onPinButtonClicked(5)
+
+ assertThat(entries).hasSize(3)
+ assertThat(entries?.map { it.input }).containsExactly(1, 4, 5).inOrder()
+ assertThat(entries?.map { it.sequenceNumber }).isInStrictOrder()
+ }
+
+ @Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -165,13 +193,9 @@
underTest.onPinButtonClicked(4)
underTest.onBackspaceButtonLongPressed()
- repeat(4) { index ->
- assertThat(pinLengths).isEqualTo(4 - index to 3 - index)
- advanceTimeBy(PinBouncerViewModel.BACKSPACE_LONG_PRESS_DELAY_MS)
- }
assertThat(message?.text).isEmpty()
- assertThat(pinLengths).isEqualTo(1 to 0)
+ assertThat(entries).hasSize(0)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -181,7 +205,7 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -204,8 +228,8 @@
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -219,7 +243,7 @@
underTest.onAuthenticateButtonClicked()
- assertThat(pinLengths).isEqualTo(0 to 0)
+ assertThat(entries).hasSize(0)
assertThat(message?.text).isEqualTo(WRONG_PIN)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -231,8 +255,8 @@
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
- val pinLengths by collectLastValue(underTest.pinLengths)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -245,7 +269,7 @@
underTest.onPinButtonClicked(5) // PIN is now wrong!
underTest.onAuthenticateButtonClicked()
assertThat(message?.text).isEqualTo(WRONG_PIN)
- assertThat(pinLengths).isEqualTo(0 to 0)
+ assertThat(entries).hasSize(0)
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -266,5 +290,11 @@
private const val CONTAINER_NAME = "container1"
private const val ENTER_YOUR_PIN = "Enter your pin"
private const val WRONG_PIN = "Wrong pin"
+
+ val KEY_CODE =
+ Correspondence.transforming<EnteredKey, Int>(
+ { it?.input },
+ "has a eventId of",
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 8ee7d3e..c9470bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
@@ -185,6 +186,7 @@
commandQueue = commandQueue,
featureFlags = featureFlags,
bouncerRepository = FakeKeyguardBouncerRepository(),
+ configurationRepository = FakeConfigurationRepository(),
),
registry = mock(),
lockPatternUtils = lockPatternUtils,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index f31ac00..c4a0e7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -16,11 +16,16 @@
package com.android.systemui.keyguard;
+import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION;
+import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT;
import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
+import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
+import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -35,9 +40,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
import android.app.IActivityManager;
+import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
+import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.telephony.TelephonyManager;
@@ -94,9 +102,12 @@
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.SystemSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.wm.shell.keyguard.KeyguardTransitions;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -156,18 +167,24 @@
private @Mock CentralSurfaces mCentralSurfaces;
private @Mock UiEventLogger mUiEventLogger;
private @Mock SessionTracker mSessionTracker;
+ private @Mock SystemSettings mSystemSettings;
+ private @Mock SecureSettings mSecureSettings;
+ private @Mock AlarmManager mAlarmManager;
+ private FakeSystemClock mSystemClock;
private FakeFeatureFlags mFeatureFlags;
+ private int mInitialUserId;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mFalsingCollector = new FalsingCollectorFake();
-
+ mSystemClock = new FakeSystemClock();
when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
+ mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
when(testViewRoot.getView()).thenReturn(mock(View.class));
when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
@@ -183,6 +200,12 @@
DejankUtils.setImmediate(true);
createAndStartViewMediator();
+ mInitialUserId = KeyguardUpdateMonitor.getCurrentUser();
+ }
+
+ @After
+ public void teardown() {
+ KeyguardUpdateMonitor.setCurrentUser(mInitialUserId);
}
@Test
@@ -369,6 +392,49 @@
}
@Test
+ public void lockAfterScreenTimeoutUsesValueFromSettings() {
+ int currentUserId = 99;
+ int userSpecificTimeout = 5999;
+ KeyguardUpdateMonitor.setCurrentUser(currentUserId);
+
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
+ when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L);
+ when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout);
+ mSystemClock.setElapsedRealtime(0L);
+ ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class);
+
+ mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_TIMEOUT);
+
+ verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture());
+ assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction());
+ }
+
+ @Test
+ public void lockAfterSpecifiedAfterDreamStarted() {
+ int currentUserId = 99;
+ int userSpecificTimeout = 5999;
+ KeyguardUpdateMonitor.setCurrentUser(currentUserId);
+
+ // set mDeviceInteractive to true
+ mViewMediator.onStartedWakingUp(WAKE_REASON_WAKE_MOTION, false);
+ mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false);
+ when(mLockPatternUtils.isSecure(currentUserId)).thenReturn(true);
+ when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L);
+ when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout);
+ mSystemClock.setElapsedRealtime(0L);
+ ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class);
+
+ mViewMediator.onDreamingStarted();
+
+ verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture());
+ assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction());
+ }
+
+ @Test
public void testHideSurfaceBehindKeyguardMarksKeyguardNotGoingAway() {
mViewMediator.hideSurfaceBehindKeyguard();
@@ -629,7 +695,10 @@
() -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator,
() -> mScrimController,
- mFeatureFlags);
+ mFeatureFlags,
+ mSecureSettings,
+ mSystemSettings,
+ mSystemClock);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 78a65a8..eb97022 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -7,11 +7,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -60,13 +58,12 @@
keyguardRepository.setDozeAmount(0f)
keyguardRepository.setKeyguardGoingAway(false)
- val keyguardInteractor =
- KeyguardInteractor(
- keyguardRepository,
- FakeCommandQueue(),
- featureFlags,
- FakeKeyguardBouncerRepository()
+ val withDeps =
+ KeyguardInteractorFactory.create(
+ repository = keyguardRepository,
+ featureFlags = featureFlags,
)
+ val keyguardInteractor = withDeps.keyguardInteractor
resourceTrimmer =
ResourceTrimmer(
keyguardInteractor,
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 e61620b..3ea74e5 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
@@ -47,6 +47,7 @@
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
@@ -159,17 +160,16 @@
biometricSettingsRepository = FakeBiometricSettingsRepository()
deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
trustRepository = FakeTrustRepository()
- keyguardRepository = FakeKeyguardRepository()
- bouncerRepository = FakeKeyguardBouncerRepository()
featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
- fakeCommandQueue = FakeCommandQueue()
- keyguardInteractor =
- KeyguardInteractor(
- keyguardRepository,
- fakeCommandQueue,
- featureFlags,
- bouncerRepository
+ val withDeps =
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
)
+ keyguardInteractor = withDeps.keyguardInteractor
+ keyguardRepository = withDeps.repository
+ bouncerRepository = withDeps.bouncerRepository
+ fakeCommandQueue = withDeps.commandQueue
+
alternateBouncerInteractor =
AlternateBouncerInteractor(
bouncerRepository = bouncerRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 0d695aa..a4f19b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
@@ -50,6 +51,7 @@
private lateinit var underTest: KeyguardInteractor
private lateinit var repository: FakeKeyguardRepository
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
+ private lateinit var configurationRepository: FakeConfigurationRepository
@Before
fun setUp() {
@@ -59,12 +61,14 @@
testScope = TestScope()
repository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
+ configurationRepository = FakeConfigurationRepository()
underTest =
KeyguardInteractor(
repository,
commandQueue,
featureFlags,
bouncerRepository,
+ configurationRepository,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index fb21847..8f6bbc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -38,8 +38,6 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
@@ -48,7 +46,6 @@
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any
@@ -225,7 +222,6 @@
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
@Mock private lateinit var expandable: Expandable
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
@@ -309,12 +305,10 @@
underTest =
KeyguardQuickAffordanceInteractor(
keyguardInteractor =
- KeyguardInteractor(
- repository = FakeKeyguardRepository(),
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- ),
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ )
+ .keyguardInteractor,
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(
@@ -368,11 +362,11 @@
KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
- underTest.onQuickAffordanceTriggered(
- configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
- expandable = expandable,
- slotId = "",
- )
+ underTest.onQuickAffordanceTriggered(
+ configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
+ expandable = expandable,
+ slotId = "",
+ )
if (startActivity) {
if (needsToUnlockFirst) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 895c1cd..1c0b06c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -40,7 +40,6 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
@@ -53,7 +52,6 @@
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock
@@ -84,7 +82,6 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
@@ -168,15 +165,14 @@
set(Flags.FACE_AUTH_REFACTOR, true)
}
+ val withDeps =
+ KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ repository = repository,
+ )
underTest =
KeyguardQuickAffordanceInteractor(
- keyguardInteractor =
- KeyguardInteractor(
- repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- ),
+ keyguardInteractor = withDeps.keyguardInteractor,
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 603f199..c53d430 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -21,7 +21,6 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -39,7 +38,6 @@
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
@@ -74,10 +72,10 @@
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ private lateinit var featureFlags: FakeFeatureFlags
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
@@ -103,11 +101,11 @@
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
- val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
+ featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
@@ -117,7 +115,7 @@
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -126,7 +124,7 @@
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -135,7 +133,7 @@
fromGoneTransitionInteractor =
FromGoneTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -144,7 +142,7 @@
fromDozingTransitionInteractor =
FromDozingTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -153,7 +151,7 @@
fromOccludedTransitionInteractor =
FromOccludedTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -162,7 +160,7 @@
fromAlternateBouncerTransitionInteractor =
FromAlternateBouncerTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -171,7 +169,7 @@
fromPrimaryBouncerTransitionInteractor =
FromPrimaryBouncerTransitionInteractor(
scope = testScope,
- keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
keyguardSecurityModel = keyguardSecurityModel,
@@ -882,13 +880,13 @@
WakeSleepReason.OTHER
)
- private fun createKeyguardInteractor(featureFlags: FeatureFlags): KeyguardInteractor {
- return KeyguardInteractor(
- keyguardRepository,
- commandQueue,
- featureFlags,
- bouncerRepository,
- )
+ private fun createKeyguardInteractor(): KeyguardInteractor {
+ return KeyguardInteractorFactory.create(
+ featureFlags = featureFlags,
+ repository = keyguardRepository,
+ bouncerRepository = bouncerRepository,
+ )
+ .keyguardInteractor
}
private suspend fun TestScope.runTransition(from: KeyguardState, to: KeyguardState) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index d622f1c..65781c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -95,7 +95,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -108,7 +108,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.unlockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -195,7 +195,7 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 8a36dbc..a493b1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -39,12 +39,11 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -56,7 +55,6 @@
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
@@ -95,7 +93,6 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
@@ -140,7 +137,6 @@
),
),
)
- repository = FakeKeyguardRepository()
val featureFlags =
FakeFeatureFlags().apply {
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
@@ -149,13 +145,10 @@
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
}
- val keyguardInteractor =
- KeyguardInteractor(
- repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- )
+ val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ val keyguardInteractor = withDeps.keyguardInteractor
+ repository = withDeps.repository
+
whenever(userTracker.userHandle).thenReturn(mock())
whenever(userTracker.userId).thenReturn(10)
whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
@@ -550,91 +543,6 @@
}
@Test
- fun isIndicationAreaPadded() =
- testScope.runTest {
- repository.setKeyguardShowing(true)
- val value = collectLastValue(underTest.isIndicationAreaPadded)
-
- assertThat(value()).isFalse()
- setUpQuickAffordanceModel(
- position = KeyguardQuickAffordancePosition.BOTTOM_START,
- testConfig =
- TestConfig(
- isVisible = true,
- isClickable = true,
- icon = mock(),
- canShowWhileLocked = true,
- slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
- )
- )
- assertThat(value()).isTrue()
- setUpQuickAffordanceModel(
- position = KeyguardQuickAffordancePosition.BOTTOM_END,
- testConfig =
- TestConfig(
- isVisible = true,
- isClickable = true,
- icon = mock(),
- canShowWhileLocked = false,
- slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
- )
- )
- assertThat(value()).isTrue()
- setUpQuickAffordanceModel(
- position = KeyguardQuickAffordancePosition.BOTTOM_START,
- testConfig =
- TestConfig(
- isVisible = false,
- slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
- )
- )
- assertThat(value()).isTrue()
- setUpQuickAffordanceModel(
- position = KeyguardQuickAffordancePosition.BOTTOM_END,
- testConfig =
- TestConfig(
- isVisible = false,
- slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
- )
- )
- assertThat(value()).isFalse()
- }
-
- @Test
- fun indicationAreaTranslationX() =
- testScope.runTest {
- val value = collectLastValue(underTest.indicationAreaTranslationX)
-
- assertThat(value()).isEqualTo(0f)
- repository.setClockPosition(100, 100)
- assertThat(value()).isEqualTo(100f)
- repository.setClockPosition(200, 100)
- assertThat(value()).isEqualTo(200f)
- repository.setClockPosition(200, 200)
- assertThat(value()).isEqualTo(200f)
- repository.setClockPosition(300, 100)
- assertThat(value()).isEqualTo(300f)
- }
-
- @Test
- fun indicationAreaTranslationY() =
- testScope.runTest {
- val value =
- collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET))
-
- // Negative 0 - apparently there's a difference in floating point arithmetic - FML
- assertThat(value()).isEqualTo(-0f)
- val expected1 = setDozeAmountAndCalculateExpectedTranslationY(0.1f)
- assertThat(value()).isEqualTo(expected1)
- val expected2 = setDozeAmountAndCalculateExpectedTranslationY(0.2f)
- assertThat(value()).isEqualTo(expected2)
- val expected3 = setDozeAmountAndCalculateExpectedTranslationY(0.5f)
- assertThat(value()).isEqualTo(expected3)
- val expected4 = setDozeAmountAndCalculateExpectedTranslationY(1f)
- assertThat(value()).isEqualTo(expected4)
- }
-
- @Test
fun isClickable_trueWhenAlphaAtThreshold() =
testScope.runTest {
repository.setKeyguardShowing(true)
@@ -757,11 +665,6 @@
)
}
- private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float {
- repository.setDozeAmount(dozeAmount)
- return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET)
- }
-
private suspend fun setUpQuickAffordanceModel(
position: KeyguardQuickAffordancePosition,
testConfig: TestConfig,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
new file mode 100644
index 0000000..dff0f29
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+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.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
+
+ @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
+
+ private lateinit var underTest: KeyguardIndicationAreaViewModel
+ private lateinit var repository: FakeKeyguardRepository
+
+ private val startButtonFlow =
+ MutableStateFlow<KeyguardQuickAffordanceViewModel>(
+ KeyguardQuickAffordanceViewModel(
+ slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()
+ )
+ )
+ private val endButtonFlow =
+ MutableStateFlow<KeyguardQuickAffordanceViewModel>(
+ KeyguardQuickAffordanceViewModel(
+ slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId()
+ )
+ )
+ private val alphaFlow = MutableStateFlow<Float>(1f)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(burnInHelperWrapper.burnInOffset(anyInt(), any()))
+ .thenReturn(RETURNED_BURN_IN_OFFSET)
+
+ val withDeps = KeyguardInteractorFactory.create()
+ val keyguardInteractor = withDeps.keyguardInteractor
+ repository = withDeps.repository
+
+ val bottomAreaViewModel: KeyguardBottomAreaViewModel = mock()
+ whenever(bottomAreaViewModel.startButton).thenReturn(startButtonFlow)
+ whenever(bottomAreaViewModel.endButton).thenReturn(endButtonFlow)
+ whenever(bottomAreaViewModel.alpha).thenReturn(alphaFlow)
+ underTest =
+ KeyguardIndicationAreaViewModel(
+ keyguardInteractor = keyguardInteractor,
+ bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
+ keyguardBottomAreaViewModel = bottomAreaViewModel,
+ burnInHelperWrapper = burnInHelperWrapper,
+ )
+ }
+
+ @Test
+ fun alpha() = runTest {
+ val value = collectLastValue(underTest.alpha)
+
+ assertThat(value()).isEqualTo(1f)
+ alphaFlow.value = 0.1f
+ assertThat(value()).isEqualTo(0.1f)
+ alphaFlow.value = 0.5f
+ assertThat(value()).isEqualTo(0.5f)
+ alphaFlow.value = 0.2f
+ assertThat(value()).isEqualTo(0.2f)
+ alphaFlow.value = 0f
+ assertThat(value()).isEqualTo(0f)
+ }
+
+ @Test
+ fun isIndicationAreaPadded() = runTest {
+ repository.setKeyguardShowing(true)
+ val value = collectLastValue(underTest.isIndicationAreaPadded)
+
+ assertThat(value()).isFalse()
+ startButtonFlow.value = startButtonFlow.value.copy(isVisible = true)
+ assertThat(value()).isTrue()
+ endButtonFlow.value = endButtonFlow.value.copy(isVisible = true)
+ assertThat(value()).isTrue()
+ startButtonFlow.value = startButtonFlow.value.copy(isVisible = false)
+ assertThat(value()).isTrue()
+ endButtonFlow.value = endButtonFlow.value.copy(isVisible = false)
+ assertThat(value()).isFalse()
+ }
+
+ @Test
+ fun indicationAreaTranslationX() = runTest {
+ val value = collectLastValue(underTest.indicationAreaTranslationX)
+
+ assertThat(value()).isEqualTo(0f)
+ repository.setClockPosition(100, 100)
+ assertThat(value()).isEqualTo(100f)
+ repository.setClockPosition(200, 100)
+ assertThat(value()).isEqualTo(200f)
+ repository.setClockPosition(200, 200)
+ assertThat(value()).isEqualTo(200f)
+ repository.setClockPosition(300, 100)
+ assertThat(value()).isEqualTo(300f)
+ }
+
+ @Test
+ fun indicationAreaTranslationY() = runTest {
+ val value = collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET))
+
+ // Negative 0 - apparently there's a difference in floating point arithmetic - FML
+ assertThat(value()).isEqualTo(-0f)
+ val expected1 = setDozeAmountAndCalculateExpectedTranslationY(0.1f)
+ assertThat(value()).isEqualTo(expected1)
+ val expected2 = setDozeAmountAndCalculateExpectedTranslationY(0.2f)
+ assertThat(value()).isEqualTo(expected2)
+ val expected3 = setDozeAmountAndCalculateExpectedTranslationY(0.5f)
+ assertThat(value()).isEqualTo(expected3)
+ val expected4 = setDozeAmountAndCalculateExpectedTranslationY(1f)
+ assertThat(value()).isEqualTo(expected4)
+ }
+
+ private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float {
+ repository.setDozeAmount(dozeAmount)
+ return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET)
+ }
+
+ companion object {
+ private const val DEFAULT_BURN_IN_OFFSET = 5
+ private const val RETURNED_BURN_IN_OFFSET = 3
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 8ba3f0f..f0ea007 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -109,7 +109,7 @@
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
@@ -119,7 +119,7 @@
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
runCurrent()
@@ -132,7 +132,7 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
runCurrent()
@@ -145,7 +145,7 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
runCurrent()
@@ -158,7 +158,7 @@
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
new file mode 100644
index 0000000..450aadd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.notetask
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.UserHandle
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import kotlinx.coroutines.CoroutineDispatcher
+
+/**
+ * Fake for [NoteTaskBubblesController] as mocking suspending functions is not supported in the
+ * Android tree's version of mockito. Ideally the [NoteTaskBubblesController] should be implemented
+ * using an interface for effectively providing multiple implementations but as this fake primarily
+ * for dealing with old version of mockito there isn't any benefit in adding complexity.
+ */
+class FakeNoteTaskBubbleController(
+ unUsed1: Context,
+ unsUsed2: CoroutineDispatcher,
+ private val optionalBubbles: Optional<Bubbles>
+) : NoteTaskBubblesController(unUsed1, unsUsed2) {
+ override suspend fun areBubblesAvailable() = optionalBubbles.isPresent
+
+ override suspend fun showOrHideAppBubble(intent: Intent, userHandle: UserHandle, icon: Icon) {
+ optionalBubbles.ifPresentOrElse(
+ { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
+ { throw IllegalAccessException() }
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
new file mode 100644
index 0000000..baac9e0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.notetask
+
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.UserHandle
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.NoteTaskBubblesController.NoteTaskBubblesService
+import com.android.wm.shell.bubbles.Bubbles
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+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
+
+/** atest SystemUITests:NoteTaskBubblesServiceTest */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+internal class NoteTaskBubblesServiceTest : SysuiTestCase() {
+
+ @Mock private lateinit var bubbles: Bubbles
+
+ private fun createServiceBinder(bubbles: Bubbles? = this.bubbles) =
+ NoteTaskBubblesService(Optional.ofNullable(bubbles)).onBind(Intent())
+ as INoteTaskBubblesService
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun areBubblesAvailable_bubblesNotNull_shouldReturnTrue() {
+ assertThat(createServiceBinder().areBubblesAvailable()).isTrue()
+ }
+
+ @Test
+ fun areBubblesAvailable_bubblesNull_shouldReturnFalse() {
+ assertThat(createServiceBinder(bubbles = null).areBubblesAvailable()).isFalse()
+ }
+
+ @Test
+ fun showOrHideAppBubble() {
+ val intent = Intent()
+ val user = UserHandle.SYSTEM
+ val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+
+ createServiceBinder().showOrHideAppBubble(intent, user, icon)
+
+ verify(bubbles).showOrHideAppBubble(intent, user, icon)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index e99f8b6..204077b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -36,12 +36,12 @@
import android.content.pm.PackageManager
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.pm.UserInfo
import android.graphics.drawable.Icon
import android.os.UserHandle
import android.os.UserManager
+import android.provider.Settings
import androidx.test.ext.truth.content.IntentSubject.assertThat
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
@@ -56,22 +56,28 @@
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
-import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.SecureSettings
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles
import com.google.common.truth.Truth.assertThat
import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
@@ -80,6 +86,7 @@
import org.mockito.MockitoAnnotations
/** atest SystemUITests:NoteTaskControllerTest */
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
internal class NoteTaskControllerTest : SysuiTestCase() {
@@ -97,7 +104,10 @@
@Mock private lateinit var shortcutManager: ShortcutManager
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ @Mock private lateinit var secureSettings: SecureSettings
private val userTracker = FakeUserTracker()
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
@Before
fun setUp() {
@@ -105,7 +115,11 @@
whenever(context.getString(R.string.note_task_button_label))
.thenReturn(NOTE_TASK_SHORT_LABEL)
+ whenever(context.getString(eq(R.string.note_task_shortcut_long_label), any()))
+ .thenReturn(NOTE_TASK_LONG_LABEL)
whenever(context.packageManager).thenReturn(packageManager)
+ whenever(packageManager.getApplicationInfo(any(), any<Int>())).thenReturn(mock())
+ whenever(packageManager.getApplicationLabel(any())).thenReturn(NOTE_TASK_LONG_LABEL)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(NOTE_TASK_INFO)
whenever(userManager.isUserUnlocked).thenReturn(true)
whenever(userManager.isUserUnlocked(any<Int>())).thenReturn(true)
@@ -122,6 +136,7 @@
whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList())
whenever(userManager.isManagedProfile(workUserInfo.id)).thenReturn(true)
whenever(context.resources).thenReturn(getContext().resources)
+ whenever(secureSettings.userTracker).thenReturn(userTracker)
}
private fun createNoteTaskController(
@@ -132,7 +147,6 @@
context = context,
resolver = resolver,
eventLogger = eventLogger,
- optionalBubbles = Optional.ofNullable(bubbles),
userManager = userManager,
keyguardManager = keyguardManager,
isEnabled = isEnabled,
@@ -141,6 +155,10 @@
roleManager = roleManager,
shortcutManager = shortcutManager,
activityManager = activityManager,
+ secureSettings = secureSettings,
+ noteTaskBubblesController =
+ FakeNoteTaskBubbleController(context, testDispatcher, Optional.ofNullable(bubbles)),
+ applicationScope = testScope,
)
// region onBubbleExpandChanged
@@ -156,7 +174,7 @@
)
verify(eventLogger).logNoteTaskOpened(expectedInfo)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager)
}
@Test
@@ -171,7 +189,7 @@
)
verify(eventLogger).logNoteTaskClosed(expectedInfo)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager)
}
@Test
@@ -185,7 +203,7 @@
key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager, eventLogger)
}
@Test
@@ -199,7 +217,7 @@
key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager, eventLogger)
}
@Test
@@ -210,7 +228,7 @@
key = "any other key",
)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager, eventLogger)
}
@Test
@@ -221,7 +239,7 @@
key = Bubble.getAppBubbleKeyForApp(NOTE_TASK_INFO.packageName, NOTE_TASK_INFO.user),
)
- verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
+ verifyZeroInteractions(bubbles, keyguardManager, userManager, eventLogger)
}
// endregion
@@ -251,6 +269,44 @@
}
@Test
+ fun showNoteTask_defaultUserSet_shouldStartActivityWithExpectedUserAndLogUiEvent() {
+ whenever(secureSettings.getInt(eq(Settings.Secure.DEFAULT_NOTE_TASK_PROFILE), any()))
+ .thenReturn(10)
+ val user10 = UserHandle.of(/* userId= */ 10)
+
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(
+ entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
+ isKeyguardLocked = true,
+ user = user10,
+ )
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController()
+ .showNoteTask(
+ entryPoint = expectedInfo.entryPoint!!,
+ )
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ intentCaptor.value.let { intent ->
+ assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
+ assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
+ assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK)
+ .isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK)
+ assertThat(intent.flags and FLAG_ACTIVITY_NEW_DOCUMENT)
+ .isEqualTo(FLAG_ACTIVITY_NEW_DOCUMENT)
+ assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
+ }
+ assertThat(userCaptor.value).isEqualTo(user10)
+ verify(eventLogger).logNoteTaskOpened(expectedInfo)
+ verifyZeroInteractions(bubbles)
+ }
+
+ @Test
fun showNoteTaskWithUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
val user10 = UserHandle.of(/* userId= */ 10)
val expectedInfo =
@@ -309,7 +365,7 @@
createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
// Context package name used to create bubble icon from drawable resource id
- verify(context).packageName
+ verify(context, atLeastOnce()).packageName
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
verifyZeroInteractions(eventLogger)
}
@@ -318,7 +374,7 @@
fun showNoteTask_bubblesIsNull_shouldDoNothing() {
createNoteTaskController(bubbles = null).showNoteTask(entryPoint = TAIL_BUTTON)
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
@@ -330,14 +386,14 @@
noteTaskController.showNoteTask(entryPoint = TAIL_BUTTON)
verify(noteTaskController).showNoDefaultNotesAppToast()
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
fun showNoteTask_flagDisabled_shouldDoNothing() {
createNoteTaskController(isEnabled = false).showNoteTask(entryPoint = TAIL_BUTTON)
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
@@ -346,7 +402,7 @@
createNoteTaskController().showNoteTask(entryPoint = TAIL_BUTTON)
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
@@ -466,7 +522,7 @@
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
@@ -482,7 +538,7 @@
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
- verifyZeroInteractions(context, bubbles, eventLogger)
+ verifyZeroInteractions(bubbles, eventLogger)
}
@Test
@@ -594,11 +650,11 @@
createNoteTaskController(isEnabled = true).onRoleHoldersChanged("NOT_NOTES", user)
- verifyZeroInteractions(context)
+ verify(context, never()).startActivityAsUser(any(), any())
}
@Test
- fun onRoleHoldersChanged_notesRole_sameUser_shouldUpdateShortcuts() {
+ fun onRoleHoldersChanged_notesRole_shouldUpdateShortcuts() {
val user = userTracker.userHandle
val controller = spy(createNoteTaskController())
doNothing().whenever(controller).updateNoteTaskAsUser(any())
@@ -607,22 +663,41 @@
verify(controller).updateNoteTaskAsUser(user)
}
-
- @Test
- fun onRoleHoldersChanged_notesRole_differentUser_shouldUpdateShortcutsInUserProcess() {
- // FakeUserTracker will default to UserHandle.SYSTEM.
- val user = UserHandle.CURRENT
-
- createNoteTaskController(isEnabled = true).onRoleHoldersChanged(ROLE_NOTES, user)
-
- verify(context).startServiceAsUser(any(), eq(user))
- }
// endregion
// region updateNoteTaskAsUser
@Test
- fun updateNoteTaskAsUser_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
- createNoteTaskController(isEnabled = true).updateNoteTaskAsUser(userTracker.userHandle)
+ fun updateNoteTaskAsUser_sameUser_shouldUpdateShortcuts() {
+ val user = userTracker.userHandle
+ val controller = spy(createNoteTaskController())
+ doNothing().whenever(controller).updateNoteTaskAsUserInternal(any())
+
+ controller.updateNoteTaskAsUser(user)
+
+ verify(controller).updateNoteTaskAsUserInternal(user)
+ verify(context, never()).startServiceAsUser(any(), any())
+ }
+
+ @Test
+ fun updateNoteTaskAsUser_differentUser_shouldUpdateShortcutsInUserProcess() {
+ // FakeUserTracker will default to UserHandle.SYSTEM.
+ val user = UserHandle.CURRENT
+ val controller = spy(createNoteTaskController(isEnabled = true))
+ doNothing().whenever(controller).updateNoteTaskAsUserInternal(any())
+
+ controller.updateNoteTaskAsUser(user)
+
+ verify(controller, never()).updateNoteTaskAsUserInternal(any())
+ val intent = withArgCaptor { verify(context).startServiceAsUser(capture(), eq(user)) }
+ assertThat(intent).hasComponentClass(NoteTaskControllerUpdateService::class.java)
+ }
+ // endregion
+
+ // region internalUpdateNoteTaskAsUser
+ @Test
+ fun updateNoteTaskAsUserInternal_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
+ createNoteTaskController(isEnabled = true)
+ .updateNoteTaskAsUserInternal(userTracker.userHandle)
val actualComponent = argumentCaptor<ComponentName>()
verify(context.packageManager)
@@ -635,27 +710,29 @@
.isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
verify(shortcutManager, never()).disableShortcuts(any())
verify(shortcutManager).enableShortcuts(listOf(SHORTCUT_ID))
- val actualShortcuts = argumentCaptor<List<ShortcutInfo>>()
- verify(shortcutManager).updateShortcuts(actualShortcuts.capture())
- val actualShortcut = actualShortcuts.value.first()
- assertThat(actualShortcut.id).isEqualTo(SHORTCUT_ID)
- assertThat(actualShortcut.intent).run {
- hasComponentClass(LaunchNoteTaskActivity::class.java)
- hasAction(ACTION_CREATE_NOTE)
+ val shortcutInfo = withArgCaptor { verify(shortcutManager).updateShortcuts(capture()) }
+ with(shortcutInfo.first()) {
+ assertThat(id).isEqualTo(SHORTCUT_ID)
+ assertThat(intent).run {
+ hasComponentClass(LaunchNoteTaskActivity::class.java)
+ hasAction(ACTION_CREATE_NOTE)
+ }
+ assertThat(shortLabel).isEqualTo(NOTE_TASK_SHORT_LABEL)
+ assertThat(longLabel).isEqualTo(NOTE_TASK_LONG_LABEL)
+ assertThat(isLongLived).isEqualTo(true)
+ assertThat(icon.resId).isEqualTo(R.drawable.ic_note_task_shortcut_widget)
+ assertThat(extras?.getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE))
+ .isEqualTo(NOTE_TASK_PACKAGE_NAME)
}
- assertThat(actualShortcut.shortLabel).isEqualTo(NOTE_TASK_SHORT_LABEL)
- assertThat(actualShortcut.isLongLived).isEqualTo(true)
- assertThat(actualShortcut.icon.resId).isEqualTo(R.drawable.ic_note_task_shortcut_widget)
- assertThat(actualShortcut.extras?.getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE))
- .isEqualTo(NOTE_TASK_PACKAGE_NAME)
}
@Test
- fun updateNoteTaskAsUser_noNotesRole_shouldDisableShortcuts() {
+ fun updateNoteTaskAsUserInternal_noNotesRole_shouldDisableShortcuts() {
whenever(roleManager.getRoleHoldersAsUser(ROLE_NOTES, userTracker.userHandle))
.thenReturn(emptyList())
- createNoteTaskController(isEnabled = true).updateNoteTaskAsUser(userTracker.userHandle)
+ createNoteTaskController(isEnabled = true)
+ .updateNoteTaskAsUserInternal(userTracker.userHandle)
val argument = argumentCaptor<ComponentName>()
verify(context.packageManager)
@@ -672,8 +749,9 @@
}
@Test
- fun updateNoteTaskAsUser_flagDisabled_shouldDisableShortcuts() {
- createNoteTaskController(isEnabled = false).updateNoteTaskAsUser(userTracker.userHandle)
+ fun updateNoteTaskAsUserInternal_flagDisabled_shouldDisableShortcuts() {
+ createNoteTaskController(isEnabled = false)
+ .updateNoteTaskAsUserInternal(userTracker.userHandle)
val argument = argumentCaptor<ComponentName>()
verify(context.packageManager)
@@ -690,18 +768,17 @@
}
// endregion
- // startregion startNoteTaskProxyActivityForUser
+ // startregion updateNoteTaskForAllUsers
@Test
- fun startNoteTaskProxyActivityForUser_shouldStartLaunchNoteTaskProxyActivityWithExpectedUser() {
- val user0 = UserHandle.of(0)
- createNoteTaskController().startNoteTaskProxyActivityForUser(user0)
+ fun updateNoteTaskForAllUsers_shouldRunUpdateForCurrentUserAndProfiles() {
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+ val controller = spy(createNoteTaskController())
+ doNothing().whenever(controller).updateNoteTaskAsUser(any())
- val intentCaptor = argumentCaptor<Intent>()
- verify(context).startActivityAsUser(intentCaptor.capture(), eq(user0))
- assertThat(intentCaptor.value).run {
- hasComponentClass(LaunchNoteTaskManagedProfileProxyActivity::class.java)
- hasFlags(FLAG_ACTIVITY_NEW_TASK)
- }
+ controller.updateNoteTaskForCurrentUserAndManagedProfiles()
+
+ verify(controller).updateNoteTaskAsUser(mainUserInfo.userHandle)
+ verify(controller).updateNoteTaskAsUser(workUserInfo.userHandle)
}
// endregion
@@ -821,7 +898,8 @@
// endregion
private companion object {
- const val NOTE_TASK_SHORT_LABEL = "Notetaking"
+ const val NOTE_TASK_SHORT_LABEL = "Note-taking"
+ const val NOTE_TASK_LONG_LABEL = "Note-taking, App"
const val NOTE_TASK_ACTIVITY_NAME = "NoteTaskActivity"
const val NOTE_TASK_PACKAGE_NAME = "com.android.note.app"
const val NOTE_TASK_UID = 123456
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index 4e85b6c..95bb3e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -32,9 +32,12 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.FakeSystemClock
import com.android.wm.shell.bubbles.Bubbles
+import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
@@ -71,19 +74,19 @@
}
private fun createUnderTest(
- isEnabled: Boolean,
- bubbles: Bubbles?,
+ isEnabled: Boolean,
+ bubbles: Bubbles?,
): NoteTaskInitializer =
- NoteTaskInitializer(
- controller = controller,
- commandQueue = commandQueue,
- optionalBubbles = Optional.ofNullable(bubbles),
- isEnabled = isEnabled,
- roleManager = roleManager,
- userTracker = userTracker,
- keyguardUpdateMonitor = keyguardMonitor,
- backgroundExecutor = executor,
- )
+ NoteTaskInitializer(
+ controller = controller,
+ commandQueue = commandQueue,
+ optionalBubbles = Optional.ofNullable(bubbles),
+ isEnabled = isEnabled,
+ roleManager = roleManager,
+ userTracker = userTracker,
+ keyguardUpdateMonitor = keyguardMonitor,
+ backgroundExecutor = executor,
+ )
@Test
fun initialize_withUserUnlocked() {
@@ -93,8 +96,8 @@
verify(commandQueue).addCallback(any())
verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
- verify(controller).setNoteTaskShortcutEnabled(any(), any())
- verify(keyguardMonitor, never()).registerCallback(any())
+ verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
+ verify(keyguardMonitor).registerCallback(any())
}
@Test
@@ -107,6 +110,7 @@
verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
verify(controller, never()).setNoteTaskShortcutEnabled(any(), any())
verify(keyguardMonitor).registerCallback(any())
+ assertThat(userTracker.callbacks).isNotEmpty()
}
@Test
@@ -116,12 +120,12 @@
underTest.initialize()
verifyZeroInteractions(
- commandQueue,
- bubbles,
- controller,
- roleManager,
- userManager,
- keyguardMonitor,
+ commandQueue,
+ bubbles,
+ controller,
+ roleManager,
+ userManager,
+ keyguardMonitor,
)
}
@@ -132,12 +136,12 @@
underTest.initialize()
verifyZeroInteractions(
- commandQueue,
- bubbles,
- controller,
- roleManager,
- userManager,
- keyguardMonitor,
+ commandQueue,
+ bubbles,
+ controller,
+ roleManager,
+ userManager,
+ keyguardMonitor,
)
}
@@ -146,7 +150,7 @@
val expectedKeyEvent = KeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL)
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
- val callback = captureArgument { verify(commandQueue).addCallback(capture()) }
+ val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
callback.handleSystemKey(expectedKeyEvent)
@@ -154,31 +158,49 @@
}
@Test
- fun initialize_userUnlocked() {
+ fun initialize_userUnlocked_shouldUpdateNoteTask() {
whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(false)
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
- val callback = captureArgument { verify(keyguardMonitor).registerCallback(capture()) }
+ val callback = withArgCaptor { verify(keyguardMonitor).registerCallback(capture()) }
whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
callback.onUserUnlocked()
- verify(controller).setNoteTaskShortcutEnabled(any(), any())
+
+ verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
}
@Test
- fun initialize_onRoleHoldersChanged() {
+ fun initialize_onRoleHoldersChanged_shouldRunOnRoleHoldersChanged() {
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
- val callback = captureArgument {
+ val callback = withArgCaptor {
verify(roleManager)
- .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL))
+ .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL))
}
callback.onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle)
verify(controller).onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle)
}
-}
-private inline fun <reified T : Any> captureArgument(block: ArgumentCaptor<T>.() -> Unit) =
- argumentCaptor<T>().apply(block).value
+ @Test
+ fun initialize_onProfilesChanged_shouldUpdateNoteTask() {
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+
+ userTracker.callbacks.first().onProfilesChanged(emptyList())
+
+ verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
+ }
+
+ @Test
+ fun initialize_onUserChanged_shouldUpdateNoteTask() {
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+
+ userTracker.callbacks.first().onUserChanged(0, mock())
+
+ verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
index a0c376f..627c4a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
@@ -17,9 +17,6 @@
package com.android.systemui.notetask.shortcut
import android.content.Intent
-import android.content.pm.UserInfo
-import android.os.UserHandle
-import android.os.UserManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -29,17 +26,14 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
-import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.whenever
import org.junit.After
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.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -48,8 +42,6 @@
class LaunchNoteTaskActivityTest : SysuiTestCase() {
@Mock lateinit var noteTaskController: NoteTaskController
- @Mock lateinit var userManager: UserManager
- private val userTracker: FakeUserTracker = FakeUserTracker()
@Rule
@JvmField
@@ -60,8 +52,6 @@
override fun create(intent: Intent?) =
LaunchNoteTaskActivity(
controller = noteTaskController,
- userManager = userManager,
- userTracker = userTracker
)
},
/* initialTouchMode= */ false,
@@ -71,7 +61,6 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(userManager.isManagedProfile(eq(workProfileUser.id))).thenReturn(true)
}
@After
@@ -83,36 +72,7 @@
fun startActivityOnNonWorkProfileUser_shouldLaunchNoteTask() {
activityRule.launchActivity(/* startIntent= */ null)
- verify(noteTaskController).showNoteTask(eq(NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT))
- }
-
- @Test
- fun startActivityOnWorkProfileUser_shouldLaunchProxyActivity() {
- val mainUserHandle: UserHandle = mainUser.userHandle
- userTracker.set(listOf(mainUser, workProfileUser), selectedUserIndex = 1)
- whenever(userManager.isManagedProfile).thenReturn(true)
- whenever(userManager.mainUser).thenReturn(mainUserHandle)
-
- activityRule.launchActivity(/* startIntent= */ null)
-
- verify(noteTaskController).startNoteTaskProxyActivityForUser(eq(mainUserHandle))
- }
-
- @Test
- fun startActivityOnWorkProfileUser_noMainUser_shouldNotLaunch() {
- userTracker.set(listOf(mainUser, workProfileUser), selectedUserIndex = 1)
- whenever(userManager.isManagedProfile).thenReturn(true)
- whenever(userManager.mainUser).thenReturn(null)
-
- activityRule.launchActivity(/* startIntent= */ null)
-
- verify(noteTaskController, never()).showNoteTask(any())
- verify(noteTaskController, never()).startNoteTaskProxyActivityForUser(any())
- }
-
- private companion object {
- val mainUser = UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN)
- val workProfileUser =
- UserInfo(/* id= */ 10, /* name= */ "work", /* flags= */ UserInfo.FLAG_PROFILE)
+ verify(noteTaskController)
+ .showNoteTaskAsUser(eq(NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT), any())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivityTest.kt
deleted file mode 100644
index 6347c34..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskManagedProfileProxyActivityTest.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.notetask.shortcut
-
-import android.content.Intent
-import android.content.pm.UserInfo
-import android.os.UserHandle
-import android.os.UserManager
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
-import com.android.dx.mockito.inline.extended.ExtendedMockito.never
-import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.notetask.NoteTaskController
-import com.android.systemui.notetask.NoteTaskEntryPoint
-import com.android.systemui.settings.FakeUserTracker
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.whenever
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-@TestableLooper.RunWithLooper
-class LaunchNoteTaskManagedProfileProxyActivityTest : SysuiTestCase() {
-
- @Mock lateinit var noteTaskController: NoteTaskController
- @Mock lateinit var userManager: UserManager
- private val userTracker = FakeUserTracker()
-
- @Rule
- @JvmField
- val activityRule =
- ActivityTestRule<LaunchNoteTaskManagedProfileProxyActivity>(
- /* activityFactory= */ object :
- SingleActivityFactory<LaunchNoteTaskManagedProfileProxyActivity>(
- LaunchNoteTaskManagedProfileProxyActivity::class.java
- ) {
- override fun create(intent: Intent?) =
- LaunchNoteTaskManagedProfileProxyActivity(
- controller = noteTaskController,
- userManager = userManager,
- userTracker = userTracker
- )
- },
- /* initialTouchMode= */ false,
- /* launchActivity= */ false,
- )
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- whenever(userManager.isManagedProfile(eq(workProfileUser.id))).thenReturn(true)
- }
-
- @After
- fun tearDown() {
- activityRule.finishActivity()
- }
-
- @Test
- fun startActivity_noWorkProfileUser_shouldNotLaunchNoteTask() {
- userTracker.set(listOf(mainUser), selectedUserIndex = 0)
- activityRule.launchActivity(/* startIntent= */ null)
-
- verify(noteTaskController, never()).showNoteTaskAsUser(any(), any())
- }
-
- @Test
- fun startActivity_hasWorkProfileUser_shouldLaunchNoteTaskOnTheWorkProfileUser() {
- userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUser))
- activityRule.launchActivity(/* startIntent= */ null)
-
- val workProfileUserHandle: UserHandle = workProfileUser.userHandle
- verify(noteTaskController)
- .showNoteTaskAsUser(
- eq(NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT),
- eq(workProfileUserHandle)
- )
- }
-
- private companion object {
- val mainUser = UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN)
- val workProfileUser =
- UserInfo(/* id= */ 10, /* name= */ "work", /* flags= */ UserInfo.FLAG_PROFILE)
- val mainAndWorkProfileUsers = listOf(mainUser, workProfileUser)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 105387d..05a1699 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -70,7 +70,7 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
runCurrent()
@@ -83,7 +83,7 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 3def6ba..f2812b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -16,9 +16,11 @@
package com.android.systemui.screenrecord;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -32,6 +34,7 @@
import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -41,7 +44,9 @@
import com.android.systemui.media.MediaProjectionCaptureTarget;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
@@ -77,20 +82,38 @@
private UserContextProvider mUserContextTracker;
@Captor
private ArgumentCaptor<Runnable> mRunnableCaptor;
- private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() {
- public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
- boolean requiresShadeOpen) {
- action.onDismiss();
- }
- };
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
+ private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil(
+ mKeyguardStateController, mStatusBarStateController, mActivityStarter);
private RecordingService mRecordingService;
+ private class RecordingServiceTestable extends RecordingService {
+ RecordingServiceTestable(
+ RecordingController controller, Executor executor,
+ Handler handler, UiEventLogger uiEventLogger,
+ NotificationManager notificationManager,
+ UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
+ super(controller, executor, handler,
+ uiEventLogger, notificationManager, userContextTracker, keyguardDismissUtil);
+ attachBaseContext(mContext);
+ }
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mHandler,
- mUiEventLogger, mNotificationManager, mUserContextTracker, mKeyguardDismissUtil));
+ mRecordingService = Mockito.spy(new RecordingServiceTestable(mController, mExecutor,
+ mHandler, mUiEventLogger, mNotificationManager,
+ mUserContextTracker, mKeyguardDismissUtil));
// Return actual context info
doReturn(mContext).when(mRecordingService).getApplicationContext();
@@ -160,8 +183,7 @@
Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, null);
mRecordingService.onStartCommand(startIntent, 0, 0);
- // Then the state is set to not recording
- verify(mController).updateState(false);
+ assertUpdateState(false);
}
@Test
@@ -179,7 +201,7 @@
mRecordingService.onStopped();
- verify(mController).updateState(false);
+ assertUpdateState(false);
}
@Test
@@ -224,8 +246,21 @@
verify(mExecutor).execute(mRunnableCaptor.capture());
mRunnableCaptor.getValue().run();
- // Then the state is set to not recording and we cancel the notification
- verify(mController).updateState(false);
+ assertUpdateState(false);
verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
}
+
+ private void assertUpdateState(boolean state) {
+ // Then the state is set to not recording, and we cancel the notification
+ // non SYSTEM user doesn't have the reference to the correct controller,
+ // so a broadcast is sent in case of non SYSTEM user.
+ if (UserHandle.USER_SYSTEM == mContext.getUserId()) {
+ verify(mController).updateState(state);
+ } else {
+ ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mRecordingService).sendBroadcast(argumentCaptor.capture(), eq(PERMISSION_SELF));
+ assertEquals(RecordingController.INTENT_UPDATE_STATE,
+ argumentCaptor.getValue().getAction());
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
index 67b1099..d8897e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
@@ -16,14 +16,17 @@
package com.android.systemui.screenshot.appclips;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
+
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
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.eq;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
@@ -31,8 +34,6 @@
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
import androidx.test.runner.AndroidJUnit4;
@@ -46,7 +47,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;
@@ -63,7 +63,6 @@
@Mock private Optional<Bubbles> mOptionalBubbles;
@Mock private Bubbles mBubbles;
@Mock private DevicePolicyManager mDevicePolicyManager;
- @Mock private UserManager mUserManager;
private AppClipsService mAppClipsService;
@@ -81,51 +80,84 @@
}
@Test
+ public void flagOff_internal_shouldReturnFailed() throws RemoteException {
+ when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(false);
+
+ assertThat(getInterfaceWithRealContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
+ }
+
+ @Test
public void emptyBubbles_shouldReturnFalse() throws RemoteException {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(true);
+ mockForEmptyBubbles();
assertThat(getInterfaceWithRealContext()
.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isFalse();
}
@Test
+ public void emptyBubbles_internal_shouldReturnFailed() throws RemoteException {
+ mockForEmptyBubbles();
+
+ assertThat(getInterfaceWithRealContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
+ }
+
+ @Test
public void taskIdNotAppBubble_shouldReturnFalse() throws RemoteException {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(false);
+ mockForTaskIdNotAppBubble();
assertThat(getInterfaceWithRealContext()
.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isFalse();
}
@Test
+ public void taskIdNotAppBubble_internal_shouldReturnWindowUnsupported() throws RemoteException {
+ mockForTaskIdNotAppBubble();
+
+ assertThat(getInterfaceWithRealContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED);
+ }
+
+ @Test
public void dpmScreenshotBlocked_shouldReturnFalse() throws RemoteException {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(true);
- when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(true);
+ mockForScreenshotBlocked();
assertThat(getInterfaceWithRealContext()
.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isFalse();
}
@Test
+ public void dpmScreenshotBlocked_internal_shouldReturnBlockedByAdmin() throws RemoteException {
+ mockForScreenshotBlocked();
+
+ assertThat(getInterfaceWithRealContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN);
+ }
+
+ @Test
public void configComponentNameNotValid_shouldReturnFalse() throws RemoteException {
- when(mMockContext.getString(anyInt())).thenReturn(EMPTY);
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(true);
- when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
+ mockForInvalidConfigComponentName();
assertThat(getInterfaceWithMockContext()
.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isFalse();
}
@Test
+ public void configComponentNameNotValid_internal_shouldReturnFailed() throws RemoteException {
+ mockForInvalidConfigComponentName();
+
+ assertThat(getInterfaceWithMockContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
+ }
+
+
+ @Test
public void allPrerequisitesSatisfy_shouldReturnTrue() throws RemoteException {
mockToSatisfyAllPrerequisites();
@@ -134,28 +166,44 @@
}
@Test
- public void isManagedProfile_shouldUseProxyConnection() throws RemoteException {
- when(mUserManager.isManagedProfile()).thenReturn(true);
- when(mUserManager.getMainUser()).thenReturn(UserHandle.SYSTEM);
- IAppClipsService service = getInterfaceWithRealContext();
- mAppClipsService.mProxyConnectorToMainProfile =
- Mockito.spy(mAppClipsService.mProxyConnectorToMainProfile);
+ public void allPrerequisitesSatisfy_internal_shouldReturnSuccess() throws RemoteException {
+ mockToSatisfyAllPrerequisites();
- service.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID);
-
- verify(mAppClipsService.mProxyConnectorToMainProfile).postForResult(any());
+ assertThat(getInterfaceWithRealContext()
+ .canLaunchCaptureContentActivityForNoteInternal(FAKE_TASK_ID))
+ .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
}
- @Test
- public void isManagedProfile_noMainUser_shouldReturnFalse() {
- when(mUserManager.isManagedProfile()).thenReturn(true);
- when(mUserManager.getMainUser()).thenReturn(null);
-
- getInterfaceWithRealContext();
-
- assertThat(mAppClipsService.mProxyConnectorToMainProfile).isNull();
+ private void mockForEmptyBubbles() {
+ when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
+ when(mOptionalBubbles.isEmpty()).thenReturn(true);
}
+ private void mockForTaskIdNotAppBubble() {
+ when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
+ when(mOptionalBubbles.isEmpty()).thenReturn(false);
+ when(mOptionalBubbles.get()).thenReturn(mBubbles);
+ when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(false);
+ }
+
+ private void mockForScreenshotBlocked() {
+ when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
+ when(mOptionalBubbles.isEmpty()).thenReturn(false);
+ when(mOptionalBubbles.get()).thenReturn(mBubbles);
+ when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(true);
+ when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(true);
+ }
+
+ private void mockForInvalidConfigComponentName() {
+ when(mMockContext.getString(anyInt())).thenReturn(EMPTY);
+ when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
+ when(mOptionalBubbles.isEmpty()).thenReturn(false);
+ when(mOptionalBubbles.get()).thenReturn(mBubbles);
+ when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(true);
+ when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
+ }
+
+
private void mockToSatisfyAllPrerequisites() {
when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
when(mOptionalBubbles.isEmpty()).thenReturn(false);
@@ -166,13 +214,13 @@
private IAppClipsService getInterfaceWithRealContext() {
mAppClipsService = new AppClipsService(getContext(), mFeatureFlags,
- mOptionalBubbles, mDevicePolicyManager, mUserManager);
+ mOptionalBubbles, mDevicePolicyManager);
return getInterfaceFromService(mAppClipsService);
}
private IAppClipsService getInterfaceWithMockContext() {
mAppClipsService = new AppClipsService(mMockContext, mFeatureFlags,
- mOptionalBubbles, mDevicePolicyManager, mUserManager);
+ mOptionalBubbles, mDevicePolicyManager);
return getInterfaceFromService(mAppClipsService);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index e9007ff..7fad972 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -24,22 +24,19 @@
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
-import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
+import static com.android.internal.infra.AndroidFuture.completedFuture;
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
-import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_USE_WP_USER;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -52,20 +49,22 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
-import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.intercepting.SingleActivityFactory;
+import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IAppClipsService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.notetask.NoteTaskController;
-import com.android.systemui.settings.UserTracker;
-import com.android.wm.shell.bubbles.Bubbles;
+
+import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
@@ -75,8 +74,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-import java.util.Optional;
+import java.util.concurrent.Executor;
@RunWith(AndroidTestingRunner.class)
public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
@@ -86,25 +84,19 @@
private static final int TEST_UID = 42;
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
- @Mock
- private DevicePolicyManager mDevicePolicyManager;
- @Mock
- private FeatureFlags mFeatureFlags;
- @Mock
- private Optional<Bubbles> mOptionalBubbles;
- @Mock
- private Bubbles mBubbles;
+ @Mock private ServiceConnector<IAppClipsService> mServiceConnector;
@Mock
private NoteTaskController mNoteTaskController;
@Mock
private PackageManager mPackageManager;
@Mock
- private UserTracker mUserTracker;
- @Mock
private UiEventLogger mUiEventLogger;
@Mock
- private UserManager mUserManager;
-
+ private BroadcastSender mBroadcastSender;
+ @Background
+ private Executor mBgExecutor;
+ @Main
+ private Executor mMainExecutor;
@Main
private Handler mMainHandler;
@@ -114,9 +106,9 @@
new SingleActivityFactory<>(AppClipsTrampolineActivityTestable.class) {
@Override
protected AppClipsTrampolineActivityTestable create(Intent unUsed) {
- return new AppClipsTrampolineActivityTestable(mDevicePolicyManager,
- mFeatureFlags, mOptionalBubbles, mNoteTaskController, mPackageManager,
- mUserTracker, mUiEventLogger, mUserManager, mMainHandler);
+ return new AppClipsTrampolineActivityTestable(mServiceConnector,
+ mNoteTaskController, mPackageManager, mUiEventLogger, mBroadcastSender,
+ mBgExecutor, mMainExecutor, mMainHandler);
}
};
@@ -133,6 +125,8 @@
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
MockitoAnnotations.initMocks(this);
+ mBgExecutor = MoreExecutors.directExecutor();
+ mMainExecutor = MoreExecutors.directExecutor();
mMainHandler = mContext.getMainThreadHandler();
mActivityIntent = new Intent(mContext, AppClipsTrampolineActivityTestable.class);
@@ -169,19 +163,9 @@
}
@Test
- public void flagOff_shouldFinishWithResultCancel() {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(false);
-
- mActivityRule.launchActivity(mActivityIntent);
-
- assertThat(mActivityRule.getActivityResult().getResultCode())
- .isEqualTo(Activity.RESULT_CANCELED);
- }
-
- @Test
- public void bubblesEmpty_shouldFinishWithFailed() {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(true);
+ public void queryService_returnedFailed_shouldFinishWithFailed() {
+ when(mServiceConnector.postForResult(any()))
+ .thenReturn(completedFuture(CAPTURE_CONTENT_FOR_NOTE_FAILED));
mActivityRule.launchActivity(mActivityIntent);
@@ -189,14 +173,13 @@
assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK);
assertThat(getStatusCodeExtra(actualResult.getResultData()))
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
+ assertThat(mActivityRule.getActivity().isFinishing()).isTrue();
}
@Test
- public void taskIdNotAppBubble_shouldFinishWithWindowModeUnsupported() {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(false);
+ public void queryService_returnedWindowModeUnsupported_shouldFinishWithWindowModeUnsupported() {
+ when(mServiceConnector.postForResult(any()))
+ .thenReturn(completedFuture(CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED));
mActivityRule.launchActivity(mActivityIntent);
@@ -204,15 +187,13 @@
assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK);
assertThat(getStatusCodeExtra(actualResult.getResultData()))
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED);
+ assertThat(mActivityRule.getActivity().isFinishing()).isTrue();
}
@Test
- public void dpmScreenshotBlocked_shouldFinishWithBlockedByAdmin() {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
- when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(true);
+ public void queryService_returnedScreenshotBlocked_shouldFinishWithBlockedByAdmin() {
+ when(mServiceConnector.postForResult(any()))
+ .thenReturn(completedFuture(CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN));
mActivityRule.launchActivity(mActivityIntent);
@@ -220,6 +201,7 @@
assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK);
assertThat(getStatusCodeExtra(actualResult.getResultData()))
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN);
+ assertThat(mActivityRule.getActivity().isFinishing()).isTrue();
}
@Test
@@ -240,6 +222,7 @@
assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK);
assertThat(getStatusCodeExtra(actualResult.getResultData()))
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_USER_CANCELED);
+ assertThat(mActivityRule.getActivity().isFinishing()).isTrue();
}
@Test
@@ -261,6 +244,7 @@
assertThat(getStatusCodeExtra(actualResult.getResultData()))
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
assertThat(actualResult.getResultData().getData()).isEqualTo(TEST_URI);
+ assertThat(mActivityRule.getActivity().isFinishing()).isTrue();
}
@Test
@@ -274,48 +258,9 @@
verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID, TEST_CALLING_PACKAGE);
}
- @Test
- public void startAppClipsActivity_throughWPUser_shouldStartMainUserActivity()
- throws NameNotFoundException {
- when(mUserManager.isManagedProfile()).thenReturn(true);
- when(mUserManager.getMainUser()).thenReturn(UserHandle.SYSTEM);
- mockToSatisfyAllPrerequisites();
-
- AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent);
- waitForIdleSync();
-
- Intent actualIntent = activity.mStartedIntent;
- assertThat(actualIntent.getComponent()).isEqualTo(
- new ComponentName(mContext, AppClipsTrampolineActivity.class));
- assertThat(actualIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- assertThat(actualIntent.getBooleanExtra(EXTRA_USE_WP_USER, false)).isTrue();
- assertThat(activity.mStartingUser).isEqualTo(UserHandle.SYSTEM);
- }
-
- @Test
- public void startAppClipsActivity_throughWPUser_noMainUser_shouldFinishWithFailed()
- throws NameNotFoundException {
- when(mUserManager.isManagedProfile()).thenReturn(true);
- when(mUserManager.getMainUser()).thenReturn(null);
-
- mockToSatisfyAllPrerequisites();
-
- mActivityRule.launchActivity(mActivityIntent);
- waitForIdleSync();
-
- ActivityResult actualResult = mActivityRule.getActivityResult();
- assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK);
- assertThat(getStatusCodeExtra(actualResult.getResultData()))
- .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
- }
-
private void mockToSatisfyAllPrerequisites() throws NameNotFoundException {
- when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
- when(mOptionalBubbles.isEmpty()).thenReturn(false);
- when(mOptionalBubbles.get()).thenReturn(mBubbles);
- when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
- when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
- when(mUserTracker.getUserProfiles()).thenReturn(List.of());
+ when(mServiceConnector.postForResult(any()))
+ .thenReturn(completedFuture(CAPTURE_CONTENT_FOR_NOTE_SUCCESS));
ApplicationInfo testApplicationInfo = new ApplicationInfo();
testApplicationInfo.uid = TEST_UID;
@@ -330,17 +275,14 @@
Intent mStartedIntent;
UserHandle mStartingUser;
- public AppClipsTrampolineActivityTestable(DevicePolicyManager devicePolicyManager,
- FeatureFlags flags,
- Optional<Bubbles> optionalBubbles,
- NoteTaskController noteTaskController,
- PackageManager packageManager,
- UserTracker userTracker,
- UiEventLogger uiEventLogger,
- UserManager userManager,
+ public AppClipsTrampolineActivityTestable(
+ ServiceConnector<IAppClipsService> serviceServiceConnector,
+ NoteTaskController noteTaskController, PackageManager packageManager,
+ UiEventLogger uiEventLogger, BroadcastSender broadcastSender,
+ @Background Executor bgExecutor, @Main Executor mainExecutor,
@Main Handler mainHandler) {
- super(devicePolicyManager, flags, optionalBubbles, noteTaskController, packageManager,
- userTracker, uiEventLogger, userManager, mainHandler);
+ super(serviceServiceConnector, noteTaskController, packageManager, uiEventLogger,
+ broadcastSender, bgExecutor, mainExecutor, mainHandler);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index fe89a14..41351e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -89,12 +89,13 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
@@ -253,6 +254,7 @@
@Mock protected UserManager mUserManager;
@Mock protected UiEventLogger mUiEventLogger;
@Mock protected LockIconViewController mLockIconViewController;
+ @Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator;
@Mock protected KeyguardMediaController mKeyguardMediaController;
@Mock protected NavigationModeController mNavigationModeController;
@Mock protected NavigationBarController mNavigationBarController;
@@ -342,8 +344,8 @@
mMainDispatcher = getMainDispatcher();
mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(
new FakeKeyguardRepository());
- mKeyguardInteractor = new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue,
- mFeatureFlags, new FakeKeyguardBouncerRepository());
+
+ mKeyguardInteractor = KeyguardInteractorFactory.create().getKeyguardInteractor();
SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
mInteractionJankMonitor, mShadeExpansionStateManager);
@@ -611,6 +613,7 @@
mKeyuardLongPressViewModel,
mKeyguardInteractor,
mActivityStarter,
+ mKeyguardViewConfigurator,
mKeyguardFaceAuthInteractor);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 526dc8d..cde6ac0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -126,7 +126,7 @@
}
};
mNotificationShadeWindowController.setScrimsVisibilityListener((visibility) -> {});
- mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
+ mNotificationShadeWindowController.setWindowRootView(mNotificationShadeWindowView);
mNotificationShadeWindowController.attach();
verify(mWindowManager).addView(eq(mNotificationShadeWindowView), any());
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 16277de..0393bef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -21,6 +21,7 @@
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
@@ -29,14 +30,20 @@
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dock.DockManager
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.keyguard.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.keyguard.data.repository.FakeBouncerMessageRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
+import com.android.systemui.log.BouncerLogger
import com.android.systemui.multishade.data.remoteproxy.MultiShadeInputProxy
import com.android.systemui.multishade.data.repository.MultiShadeRepository
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor
@@ -54,6 +61,7 @@
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -104,7 +112,8 @@
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock
- private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+ private lateinit var unfoldTransitionProgressProvider:
+ Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@@ -134,6 +143,7 @@
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
featureFlags.set(Flags.DUAL_SHADE, false)
featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
+ featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
val inputProxy = MultiShadeInputProxy()
testScope = TestScope()
@@ -170,6 +180,7 @@
pulsingGestureListener,
keyguardBouncerViewModel,
keyguardBouncerComponentFactory,
+ mock(KeyguardMessageAreaController.Factory::class.java),
keyguardTransitionInteractor,
primaryBouncerToGoneTransitionViewModel,
featureFlags,
@@ -189,6 +200,10 @@
shadeController = shadeController,
)
},
+ BouncerMessageInteractor(FakeBouncerMessageRepository(),
+ mock(BouncerMessageFactory::class.java),
+ FakeUserRepository(), CountDownTimerUtil(), featureFlags),
+ BouncerLogger(logcatLogBuffer("BouncerLog"))
)
underTest.setupExpandedStatusBar()
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 16af208..5ae8ee1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -21,6 +21,7 @@
import android.view.MotionEvent
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
@@ -29,13 +30,19 @@
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dock.DockManager
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.keyguard.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.keyguard.data.repository.FakeBouncerMessageRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
+import com.android.systemui.log.BouncerLogger
import com.android.systemui.multishade.data.remoteproxy.MultiShadeInputProxy
import com.android.systemui.multishade.data.repository.MultiShadeRepository
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor
@@ -54,11 +61,13 @@
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.TestScope
@@ -69,10 +78,10 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.Optional
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
@@ -106,7 +115,8 @@
@Mock
private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock
- private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+ private lateinit var unfoldTransitionProgressProvider:
+ Optional<UnfoldTransitionProgressProvider>
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
@@ -146,6 +156,7 @@
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
featureFlags.set(Flags.DUAL_SHADE, false)
featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
+ featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
val inputProxy = MultiShadeInputProxy()
testScope = TestScope()
val multiShadeInteractor =
@@ -181,6 +192,7 @@
pulsingGestureListener,
keyguardBouncerViewModel,
keyguardBouncerComponentFactory,
+ Mockito.mock(KeyguardMessageAreaController.Factory::class.java),
keyguardTransitionInteractor,
primaryBouncerToGoneTransitionViewModel,
featureFlags,
@@ -200,6 +212,14 @@
shadeController = shadeController,
)
},
+ BouncerMessageInteractor(
+ FakeBouncerMessageRepository(),
+ Mockito.mock(BouncerMessageFactory::class.java),
+ FakeUserRepository(),
+ CountDownTimerUtil(),
+ featureFlags
+ ),
+ BouncerLogger(logcatLogBuffer("BouncerLog"))
)
controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 69d03d9..f8e1a9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -71,7 +71,7 @@
fun upTransitionSceneKey_deviceLocked_lockScreen() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
@@ -81,7 +81,7 @@
fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -91,7 +91,7 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.unlockDevice()
runCurrent()
@@ -104,7 +104,7 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
+ authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 542e0cb..c810f0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -102,6 +102,7 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -297,7 +298,8 @@
mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
mAlternateBouncerInteractor,
mAlarmManager,
- mUserTracker
+ mUserTracker,
+ mock(BouncerMessageInteractor.class)
);
mController.init();
mController.setIndicationArea(mIndicationArea);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index fd9f6a7..4ed113f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -287,7 +287,6 @@
@Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private PluginDependencyProvider mPluginDependencyProvider;
- @Mock private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock private ExtensionController mExtensionController;
@Mock private UserInfoControllerImpl mUserInfoControllerImpl;
@Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
@@ -516,7 +515,6 @@
mInitController,
new Handler(TestableLooper.get(this).getLooper()),
mPluginDependencyProvider,
- mKeyguardDismissUtil,
mExtensionController,
mUserInfoControllerImpl,
mPhoneStatusBarPolicy,
@@ -1103,8 +1101,10 @@
clearInvocations(mNotificationPanelViewController);
mCentralSurfaces.mWakefulnessObserver.onStartedWakingUp();
- verify(mDozeServiceHost).stopDozing();
+ verify(mDozeServiceHost, never()).stopDozing();
verify(mNotificationPanelViewController).expand(eq(false));
+ mCentralSurfaces.mWakefulnessObserver.onFinishedWakingUp();
+ verify(mDozeServiceHost).stopDozing();
}
@Test
@@ -1118,6 +1118,8 @@
mCentralSurfaces.setBouncerShowing(true);
mCentralSurfaces.mWakefulnessObserver.onStartedWakingUp();
verify(mNotificationPanelViewController, never()).expand(anyBoolean());
+ mCentralSurfaces.mWakefulnessObserver.onFinishedWakingUp();
+ verify(mDozeServiceHost).stopDozing();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
new file mode 100644
index 0000000..b0aa2d3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class KeyguardDismissUtilTest extends SysuiTestCase {
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private ActivityStarter.OnDismissAction mAction;
+
+ private KeyguardDismissUtil mKeyguardDismissUtil;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mKeyguardDismissUtil = new KeyguardDismissUtil(
+ mKeyguardStateController, mStatusBarStateController, mActivityStarter);
+ }
+
+ @Test
+ public void testSetLeaveOpenOnKeyguardHideWhenKeyGuardStateControllerIsShowing() {
+ doReturn(true).when(mKeyguardStateController).isShowing();
+
+ mKeyguardDismissUtil.executeWhenUnlocked(mAction, true /* requiresShadeOpen */,
+ true /* afterKeyguardGone */);
+
+ verify(mStatusBarStateController).setLeaveOpenOnKeyguardHide(true);
+
+ verify(mActivityStarter).dismissKeyguardThenExecute(mAction, null, true);
+
+ }
+
+ @Test
+ public void testSetLeaveOpenOnKeyguardHideWhenKeyGuardStateControllerIsNotShowing() {
+ doReturn(false).when(mKeyguardStateController).isShowing();
+
+ mKeyguardDismissUtil.executeWhenUnlocked(mAction, true /* requiresShadeOpen */,
+ true /* afterKeyguardGone */);
+
+ //no interaction with mStatusBarStateController
+ verify(mStatusBarStateController, times(0)).setLeaveOpenOnKeyguardHide(true);
+
+ verify(mActivityStarter).dismissKeyguardThenExecute(mAction, null, true);
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index fdfe028..1724f27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -44,7 +44,6 @@
import com.android.systemui.shade.ShadeNotificationPresenter;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -122,7 +121,6 @@
mock(NotificationShadeWindowController.class),
mock(DynamicPrivacyController.class),
mKeyguardStateController,
- mock(KeyguardIndicationController.class),
mCentralSurfaces,
mock(LockscreenShadeTransitionController.class),
mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 3b0d512..ae38958e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -51,9 +51,11 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -107,14 +109,15 @@
private SmartReplyInflaterImpl mSmartReplyInflater;
private SmartActionInflaterImpl mSmartActionInflater;
+ private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock private SmartReplyConstants mConstants;
@Mock private ActivityStarter mActivityStarter;
@Mock private HeadsUpManager mHeadsUpManager;
@Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock private SmartReplyController mSmartReplyController;
-
- private final KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil();
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private SysuiStatusBarStateController mStatusBarStateController;
@Before
public void setUp() {
@@ -122,12 +125,15 @@
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION),
Context.RECEIVER_EXPORTED_UNAUDITED);
- mKeyguardDismissUtil.setDismissHandler((action, unused, afterKgGone) -> action.onDismiss());
+
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectMockDependency(NotificationRemoteInputManager.class);
mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
+ mDependency.injectTestDependency(KeyguardStateController.class, mKeyguardStateController);
+ mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
+
// Any number of replies are fine.
when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(0);
@@ -153,6 +159,13 @@
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
+ mKeyguardDismissUtil = new KeyguardDismissUtil(
+ mKeyguardStateController, mStatusBarStateController, mActivityStarter) {
+ public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
+ boolean requiresShadeOpen, boolean afterKeyguardGone) {
+ action.onDismiss();
+ }
+ };
mSmartReplyInflater = new SmartReplyInflaterImpl(
mConstants,
mKeyguardDismissUtil,
@@ -185,7 +198,17 @@
@Test
public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
- mKeyguardDismissUtil.setDismissHandler((action, unused, afterKgGone) -> { });
+ mKeyguardDismissUtil = new KeyguardDismissUtil(
+ mKeyguardStateController, mStatusBarStateController, mActivityStarter) {
+ public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
+ boolean requiresShadeOpen, boolean afterKeyguardGone) { }};
+ mSmartReplyInflater = new SmartReplyInflaterImpl(
+ mConstants,
+ mKeyguardDismissUtil,
+ mNotificationRemoteInputManager,
+ mSmartReplyController,
+ mContext);
+
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -196,9 +219,20 @@
@Test
public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
+ mKeyguardDismissUtil = new KeyguardDismissUtil(
+ mKeyguardStateController, mStatusBarStateController, mActivityStarter) {
+ public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
+ boolean requiresShadeOpen, boolean afterKeyguardGone) {
+ actionRef.set(action);
+ }
+ };
+ mSmartReplyInflater = new SmartReplyInflaterImpl(
+ mConstants,
+ mKeyguardDismissUtil,
+ mNotificationRemoteInputManager,
+ mSmartReplyController,
+ mContext);
- mKeyguardDismissUtil.setDismissHandler((action, unused, afterKgGone)
- -> actionRef.set(action));
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index d9ee081..813597a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -28,12 +28,10 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.shade.ShadeFoldAnimator
import com.android.systemui.shade.ShadeViewController
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.unfold.util.FoldableDeviceStates
@@ -80,8 +78,6 @@
@Mock lateinit var viewTreeObserver: ViewTreeObserver
- @Mock private lateinit var commandQueue: CommandQueue
-
@Mock lateinit var shadeFoldAnimator: ShadeFoldAnimator
@Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
@@ -111,15 +107,10 @@
onActionStarted.run()
}
- keyguardRepository = FakeKeyguardRepository()
val featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
- val keyguardInteractor =
- KeyguardInteractor(
- repository = keyguardRepository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- )
+ val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ val keyguardInteractor = withDeps.keyguardInteractor
+ keyguardRepository = withDeps.repository
// Needs to be run on the main thread
runBlocking(IMMEDIATE) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index ca83d49..3fbbeda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -39,12 +39,10 @@
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.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -97,7 +95,6 @@
@Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
private lateinit var underTest: UserInteractor
@@ -126,8 +123,9 @@
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
+ val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ keyguardRepository = reply.repository
userRepository = FakeUserRepository()
- keyguardRepository = FakeKeyguardRepository()
telephonyRepository = FakeTelephonyRepository()
val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
@@ -142,13 +140,7 @@
applicationContext = context,
repository = userRepository,
activityStarter = activityStarter,
- keyguardInteractor =
- KeyguardInteractor(
- repository = keyguardRepository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- ),
+ keyguardInteractor = reply.keyguardInteractor,
manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index fd8c6c7..9cb26e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -32,11 +32,8 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -80,13 +77,11 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
private lateinit var underTest: StatusBarUserChipViewModel
private val userRepository = FakeUserRepository()
- private val keyguardRepository = FakeKeyguardRepository()
private lateinit var guestUserInteractor: GuestUserInteractor
private lateinit var refreshUsersScheduler: RefreshUsersScheduler
@@ -250,12 +245,8 @@
repository = userRepository,
activityStarter = activityStarter,
keyguardInteractor =
- KeyguardInteractor(
- repository = keyguardRepository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- ),
+ KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ .keyguardInteractor,
featureFlags = featureFlags,
manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 9155084..e3f9fac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -30,11 +30,9 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -79,7 +77,6 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
- @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
private lateinit var underTest: UserSwitcherViewModel
@@ -112,7 +109,6 @@
)
}
- keyguardRepository = FakeKeyguardRepository()
val refreshUsersScheduler =
RefreshUsersScheduler(
applicationScope = testScope.backgroundScope,
@@ -140,38 +136,35 @@
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
+ val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ keyguardRepository = reply.repository
+
underTest =
UserSwitcherViewModel(
- userInteractor =
- UserInteractor(
- applicationContext = context,
- repository = userRepository,
- activityStarter = activityStarter,
- keyguardInteractor =
- KeyguardInteractor(
- repository = keyguardRepository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- bouncerRepository = FakeKeyguardBouncerRepository(),
- ),
- featureFlags = featureFlags,
- manager = manager,
- headlessSystemUserMode = headlessSystemUserMode,
- applicationScope = testScope.backgroundScope,
- telephonyInteractor =
- TelephonyInteractor(
- repository = FakeTelephonyRepository(),
- ),
- broadcastDispatcher = fakeBroadcastDispatcher,
- keyguardUpdateMonitor = keyguardUpdateMonitor,
- backgroundDispatcher = testDispatcher,
- activityManager = activityManager,
- refreshUsersScheduler = refreshUsersScheduler,
- guestUserInteractor = guestUserInteractor,
- uiEventLogger = uiEventLogger,
- ),
- guestUserInteractor = guestUserInteractor,
- )
+ userInteractor =
+ UserInteractor(
+ applicationContext = context,
+ repository = userRepository,
+ activityStarter = activityStarter,
+ keyguardInteractor = reply.keyguardInteractor,
+ featureFlags = featureFlags,
+ manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
+ applicationScope = testScope.backgroundScope,
+ telephonyInteractor =
+ TelephonyInteractor(
+ repository = FakeTelephonyRepository(),
+ ),
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ backgroundDispatcher = testDispatcher,
+ activityManager = activityManager,
+ refreshUsersScheduler = refreshUsersScheduler,
+ guestUserInteractor = guestUserInteractor,
+ uiEventLogger = uiEventLogger,
+ ),
+ guestUserInteractor = guestUserInteractor,
+ )
}
@Test
@@ -323,7 +316,7 @@
setUsers(count = 2)
val isFinishRequested = mutableListOf<Boolean>()
val job =
- launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+ launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
assertThat(isFinishRequested.last()).isFalse()
underTest.onCancelButtonClicked()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 47a86b1..2158396 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -320,7 +320,7 @@
mColorExtractor, mDumpManager, mKeyguardStateController,
mScreenOffAnimationController, mAuthController, mShadeExpansionStateManager,
mShadeWindowLogger);
- mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
+ mNotificationShadeWindowController.setWindowRootView(mNotificationShadeWindowView);
mNotificationShadeWindowController.attach();
mAppBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
new file mode 100644
index 0000000..c7ca7ce
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+
+/**
+ * Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
+ * files. This should alleviate some of the burden by providing defaults for testing.
+ */
+object KeyguardInteractorFactory {
+
+ @JvmOverloads
+ @JvmStatic
+ fun create(
+ featureFlags: FakeFeatureFlags = createFakeFeatureFlags(),
+ repository: FakeKeyguardRepository = FakeKeyguardRepository(),
+ commandQueue: FakeCommandQueue = FakeCommandQueue(),
+ bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
+ configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
+ ): WithDependencies {
+ return WithDependencies(
+ repository = repository,
+ commandQueue = commandQueue,
+ featureFlags = featureFlags,
+ bouncerRepository = bouncerRepository,
+ configurationRepository = configurationRepository,
+ KeyguardInteractor(
+ repository = repository,
+ commandQueue = commandQueue,
+ featureFlags = featureFlags,
+ bouncerRepository = bouncerRepository,
+ configurationRepository = configurationRepository,
+ )
+ )
+ }
+
+ /** Provide defaults, otherwise tests will throw an error */
+ fun createFakeFeatureFlags(): FakeFeatureFlags {
+ return FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
+ }
+
+ data class WithDependencies(
+ val repository: FakeKeyguardRepository,
+ val commandQueue: FakeCommandQueue,
+ val featureFlags: FakeFeatureFlags,
+ val bouncerRepository: FakeKeyguardBouncerRepository,
+ val configurationRepository: FakeConfigurationRepository,
+ val keyguardInteractor: KeyguardInteractor,
+ )
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 995e557..d5aee92 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2859,8 +2859,7 @@
if (DEBUG) {
Slog.d(
TAG,
- addUserIdToLogMessage(
- mUserId, "Starting backup confirmation UI, token=" + token));
+ addUserIdToLogMessage(mUserId, "Starting backup confirmation UI"));
}
if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
Slog.e(
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 61fc32d..51359ad 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -163,13 +163,35 @@
private boolean mDisabledByDeviceConfig;
// Device-config settings that are cached and passed back to apps
- @GuardedBy("mLock") int mDevCfgLoggingLevel;
- @GuardedBy("mLock") int mDevCfgMaxBufferSize;
- @GuardedBy("mLock") int mDevCfgIdleFlushingFrequencyMs;
- @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs;
- @GuardedBy("mLock") int mDevCfgLogHistorySize;
- @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
- @GuardedBy("mLock") boolean mDevCfgDisableFlushForViewTreeAppearing;
+ @GuardedBy("mLock")
+ int mDevCfgLoggingLevel;
+
+ @GuardedBy("mLock")
+ int mDevCfgMaxBufferSize;
+
+ @GuardedBy("mLock")
+ int mDevCfgIdleFlushingFrequencyMs;
+
+ @GuardedBy("mLock")
+ int mDevCfgTextChangeFlushingFrequencyMs;
+
+ @GuardedBy("mLock")
+ int mDevCfgLogHistorySize;
+
+ @GuardedBy("mLock")
+ int mDevCfgIdleUnbindTimeoutMs;
+
+ @GuardedBy("mLock")
+ boolean mDevCfgDisableFlushForViewTreeAppearing;
+
+ @GuardedBy("mLock")
+ boolean mDevCfgEnableContentProtectionReceiver;
+
+ @GuardedBy("mLock")
+ int mDevCfgContentProtectionAppsBlocklistSize;
+
+ @GuardedBy("mLock")
+ int mDevCfgContentProtectionBufferSize;
private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -362,6 +384,11 @@
case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
case ContentCaptureManager
.DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING:
+ case ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
+ case ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE:
setFineTuneParamsFromDeviceConfig();
return;
default:
@@ -372,39 +399,78 @@
private void setFineTuneParamsFromDeviceConfig() {
synchronized (mLock) {
- mDevCfgMaxBufferSize = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
- ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
- mDevCfgIdleFlushingFrequencyMs = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
- ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
- mDevCfgTextChangeFlushingFrequencyMs = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
- ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
- mDevCfgLogHistorySize = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
- mDevCfgIdleUnbindTimeoutMs = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
- (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
- mDevCfgDisableFlushForViewTreeAppearing = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager
- .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
- false);
+ mDevCfgMaxBufferSize =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
+ ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
+ mDevCfgIdleFlushingFrequencyMs =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
+ ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
+ mDevCfgTextChangeFlushingFrequencyMs =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
+ ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
+ mDevCfgLogHistorySize =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE,
+ 20);
+ mDevCfgIdleUnbindTimeoutMs =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
+ (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
+ mDevCfgDisableFlushForViewTreeAppearing =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+ false);
+ mDevCfgEnableContentProtectionReceiver =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
+ mDevCfgContentProtectionAppsBlocklistSize =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE);
+ mDevCfgContentProtectionBufferSize =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager
+ .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE);
if (verbose) {
- Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): "
- + "bufferSize=" + mDevCfgMaxBufferSize
- + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
- + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
- + ", logHistory=" + mDevCfgLogHistorySize
- + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs
- + ", disableFlushForViewTreeAppearing="
- + mDevCfgDisableFlushForViewTreeAppearing);
+ Slog.v(
+ TAG,
+ "setFineTuneParamsFromDeviceConfig(): "
+ + "bufferSize="
+ + mDevCfgMaxBufferSize
+ + ", idleFlush="
+ + mDevCfgIdleFlushingFrequencyMs
+ + ", textFluxh="
+ + mDevCfgTextChangeFlushingFrequencyMs
+ + ", logHistory="
+ + mDevCfgLogHistorySize
+ + ", idleUnbindTimeoutMs="
+ + mDevCfgIdleUnbindTimeoutMs
+ + ", disableFlushForViewTreeAppearing="
+ + mDevCfgDisableFlushForViewTreeAppearing
+ + ", enableContentProtectionReceiver="
+ + mDevCfgEnableContentProtectionReceiver
+ + ", contentProtectionAppsBlocklistSize="
+ + mDevCfgContentProtectionAppsBlocklistSize
+ + ", contentProtectionBufferSize="
+ + mDevCfgContentProtectionBufferSize);
}
}
}
@@ -645,21 +711,46 @@
final String prefix2 = prefix + " ";
- pw.print(prefix); pw.print("Users disabled by Settings: "); pw.println(mDisabledBySettings);
- pw.print(prefix); pw.println("DeviceConfig Settings: ");
- pw.print(prefix2); pw.print("disabled: "); pw.println(mDisabledByDeviceConfig);
- pw.print(prefix2); pw.print("loggingLevel: "); pw.println(mDevCfgLoggingLevel);
- pw.print(prefix2); pw.print("maxBufferSize: "); pw.println(mDevCfgMaxBufferSize);
- pw.print(prefix2); pw.print("idleFlushingFrequencyMs: ");
+ pw.print(prefix);
+ pw.print("Users disabled by Settings: ");
+ pw.println(mDisabledBySettings);
+ pw.print(prefix);
+ pw.println("DeviceConfig Settings: ");
+ pw.print(prefix2);
+ pw.print("disabled: ");
+ pw.println(mDisabledByDeviceConfig);
+ pw.print(prefix2);
+ pw.print("loggingLevel: ");
+ pw.println(mDevCfgLoggingLevel);
+ pw.print(prefix2);
+ pw.print("maxBufferSize: ");
+ pw.println(mDevCfgMaxBufferSize);
+ pw.print(prefix2);
+ pw.print("idleFlushingFrequencyMs: ");
pw.println(mDevCfgIdleFlushingFrequencyMs);
- pw.print(prefix2); pw.print("textChangeFlushingFrequencyMs: ");
+ pw.print(prefix2);
+ pw.print("textChangeFlushingFrequencyMs: ");
pw.println(mDevCfgTextChangeFlushingFrequencyMs);
- pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
- pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
+ pw.print(prefix2);
+ pw.print("logHistorySize: ");
+ pw.println(mDevCfgLogHistorySize);
+ pw.print(prefix2);
+ pw.print("idleUnbindTimeoutMs: ");
pw.println(mDevCfgIdleUnbindTimeoutMs);
- pw.print(prefix2); pw.print("disableFlushForViewTreeAppearing: ");
+ pw.print(prefix2);
+ pw.print("disableFlushForViewTreeAppearing: ");
pw.println(mDevCfgDisableFlushForViewTreeAppearing);
- pw.print(prefix); pw.println("Global Options:");
+ pw.print(prefix2);
+ pw.print("enableContentProtectionReceiver: ");
+ pw.println(mDevCfgEnableContentProtectionReceiver);
+ pw.print(prefix2);
+ pw.print("contentProtectionAppsBlocklistSize: ");
+ pw.println(mDevCfgContentProtectionAppsBlocklistSize);
+ pw.print(prefix2);
+ pw.print("contentProtectionBufferSize: ");
+ pw.println(mDevCfgContentProtectionBufferSize);
+ pw.print(prefix);
+ pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
}
@@ -1019,11 +1110,19 @@
}
synchronized (mLock) {
- final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
- mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
- mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
- mDevCfgDisableFlushForViewTreeAppearing,
- whitelistedComponents);
+ final ContentCaptureOptions options =
+ new ContentCaptureOptions(
+ mDevCfgLoggingLevel,
+ mDevCfgMaxBufferSize,
+ mDevCfgIdleFlushingFrequencyMs,
+ mDevCfgTextChangeFlushingFrequencyMs,
+ mDevCfgLogHistorySize,
+ mDevCfgDisableFlushForViewTreeAppearing,
+ /* enableReceiver= */ true,
+ new ContentCaptureOptions.ContentProtectionOptions(
+ mDevCfgEnableContentProtectionReceiver,
+ mDevCfgContentProtectionBufferSize),
+ whitelistedComponents);
if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
return options;
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java
new file mode 100644
index 0000000..715cf9a
--- /dev/null
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java
@@ -0,0 +1,111 @@
+/*
+ * 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.contentprotection;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Manages whether the content protection is enabled for an app using a blocklist.
+ *
+ * @hide
+ */
+class ContentProtectionBlocklistManager {
+
+ private static final String TAG = "ContentProtectionBlocklistManager";
+
+ private static final String PACKAGE_NAME_BLOCKLIST_FILENAME =
+ "/product/etc/res/raw/content_protection/package_name_blocklist.txt";
+
+ @NonNull private final ContentProtectionPackageManager mContentProtectionPackageManager;
+
+ @Nullable private Set<String> mPackageNameBlocklist;
+
+ protected ContentProtectionBlocklistManager(
+ @NonNull ContentProtectionPackageManager contentProtectionPackageManager) {
+ mContentProtectionPackageManager = contentProtectionPackageManager;
+ }
+
+ public boolean isAllowed(@NonNull String packageName) {
+ if (mPackageNameBlocklist == null) {
+ // List not loaded or failed to load, don't run on anything
+ return false;
+ }
+ if (mPackageNameBlocklist.contains(packageName)) {
+ return false;
+ }
+ PackageInfo packageInfo = mContentProtectionPackageManager.getPackageInfo(packageName);
+ if (packageInfo == null) {
+ return false;
+ }
+ if (!mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo)) {
+ return false;
+ }
+ if (mContentProtectionPackageManager.isSystemApp(packageInfo)) {
+ return false;
+ }
+ if (mContentProtectionPackageManager.isUpdatedSystemApp(packageInfo)) {
+ return false;
+ }
+ return true;
+ }
+
+ public void updateBlocklist(int blocklistSize) {
+ Slog.i(TAG, "Blocklist size updating to: " + blocklistSize);
+ mPackageNameBlocklist = readPackageNameBlocklist(blocklistSize);
+ }
+
+ @Nullable
+ private Set<String> readPackageNameBlocklist(int blocklistSize) {
+ if (blocklistSize <= 0) {
+ // Explicitly requested an empty blocklist
+ return Collections.emptySet();
+ }
+ List<String> lines = readLinesFromRawFile(PACKAGE_NAME_BLOCKLIST_FILENAME);
+ if (lines == null) {
+ return null;
+ }
+ return lines.stream().limit(blocklistSize).collect(Collectors.toSet());
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected List<String> readLinesFromRawFile(@NonNull String filename) {
+ try (FileReader fileReader = new FileReader(filename);
+ BufferedReader bufferedReader = new BufferedReader(fileReader)) {
+ return bufferedReader
+ .lines()
+ .map(line -> line.trim())
+ .filter(line -> !line.isBlank())
+ .collect(Collectors.toList());
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to read: " + filename, ex);
+ return null;
+ }
+ }
+}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java
new file mode 100644
index 0000000..1847e5d
--- /dev/null
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.contentprotection;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager.PackageInfoFlags;
+import android.util.Slog;
+
+import java.util.Arrays;
+
+/**
+ * Basic package manager for content protection using content capture.
+ *
+ * @hide
+ */
+public class ContentProtectionPackageManager {
+
+ private static final String TAG = "ContentProtectionPackageManager";
+
+ private static final PackageInfoFlags PACKAGE_INFO_FLAGS =
+ PackageInfoFlags.of(PackageManager.GET_PERMISSIONS);
+
+ @NonNull private final PackageManager mPackageManager;
+
+ ContentProtectionPackageManager(@NonNull Context context) {
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Nullable
+ public PackageInfo getPackageInfo(@NonNull String packageName) {
+ try {
+ return mPackageManager.getPackageInfo(packageName, PACKAGE_INFO_FLAGS);
+ } catch (NameNotFoundException ex) {
+ Slog.w(TAG, "Package info not found for: " + packageName, ex);
+ return null;
+ }
+ }
+
+ public boolean isSystemApp(@NonNull PackageInfo packageInfo) {
+ return packageInfo.applicationInfo != null && isSystemApp(packageInfo.applicationInfo);
+ }
+
+ private boolean isSystemApp(@NonNull ApplicationInfo applicationInfo) {
+ return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ public boolean isUpdatedSystemApp(@NonNull PackageInfo packageInfo) {
+ return packageInfo.applicationInfo != null
+ && isUpdatedSystemApp(packageInfo.applicationInfo);
+ }
+
+ private boolean isUpdatedSystemApp(@NonNull ApplicationInfo applicationInfo) {
+ return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ }
+
+ public boolean hasRequestedInternetPermissions(@NonNull PackageInfo packageInfo) {
+ return packageInfo.requestedPermissions != null
+ && Arrays.asList(packageInfo.requestedPermissions)
+ .contains(Manifest.permission.INTERNET);
+ }
+}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 27215b2..cbacee6 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -44,7 +44,7 @@
private static final String TAG = "DynamicSystemService";
private static final long MINIMUM_SD_MB = (30L << 10);
private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
- private static final String PATH_DEFAULT = "/data/gsi/";
+ private static final String PATH_DEFAULT = "/data/gsi/dsu/";
private Context mContext;
private String mInstallPath, mDsuSlot;
private volatile IGsiService mGsiService;
@@ -226,9 +226,7 @@
IGsiService gsiService = getGsiService();
if (enable) {
try {
- if (mDsuSlot == null) {
- mDsuSlot = gsiService.getActiveDsuSlot();
- }
+ getActiveDsuSlot();
GsiServiceCallback callback = new GsiServiceCallback();
synchronized (callback) {
gsiService.enableGsiAsync(oneShot, mDsuSlot, callback);
@@ -287,4 +285,15 @@
return getGsiService().suggestScratchSize();
}
+
+ @Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+ public String getActiveDsuSlot() throws RemoteException {
+ super.getActiveDsuSlot_enforcePermission();
+
+ if (mDsuSlot == null) {
+ mDsuSlot = getGsiService().getActiveDsuSlot();
+ }
+ return mDsuSlot;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 05ca6e4..6ac1631 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -266,8 +266,12 @@
}
} else {
if (isBackgroundAuth) {
- Slog.e(TAG, "cancelling due to background auth");
- cancel();
+ Slog.e(TAG, "Sending cancel to client(Due to background auth)");
+ if (mTaskStackListener != null) {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ }
+ sendCancelOnly(getListener());
+ mCallback.onClientFinished(this, false);
} else {
// Allow system-defined limit of number of attempts before giving up
if (mShouldUseLockoutTracker) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 75709fbb..d647757 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -223,11 +223,11 @@
private final ShortTermModel mShortTermModel;
private final ShortTermModel mPausedShortTermModel;
- // Controls High Brightness Mode.
- private HighBrightnessModeController mHbmController;
+ // Controls Brightness range (including High Brightness Mode).
+ private final BrightnessRangeController mBrightnessRangeController;
// Throttles (caps) maximum allowed brightness
- private BrightnessThrottler mBrightnessThrottler;
+ private final BrightnessThrottler mBrightnessThrottler;
private boolean mIsBrightnessThrottled;
// Context-sensitive brightness configurations require keeping track of the foreground app's
@@ -257,7 +257,8 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
+ BrightnessRangeController brightnessModeController,
+ BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong, float userLux, float userBrightness) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor,
@@ -267,7 +268,7 @@
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
ambientBrightnessThresholds, screenBrightnessThresholds,
ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, context,
- hbmController, brightnessThrottler, idleModeBrightnessMapper,
+ brightnessModeController, brightnessThrottler, idleModeBrightnessMapper,
ambientLightHorizonShort, ambientLightHorizonLong, userLux, userBrightness
);
}
@@ -283,7 +284,8 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
+ BrightnessRangeController brightnessModeController,
+ BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong, float userLux, float userBrightness) {
mInjector = injector;
@@ -326,7 +328,7 @@
mPendingForegroundAppPackageName = null;
mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
- mHbmController = hbmController;
+ mBrightnessRangeController = brightnessModeController;
mBrightnessThrottler = brightnessThrottler;
mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper;
mIdleModeBrightnessMapper = idleModeBrightnessMapper;
@@ -607,10 +609,11 @@
pw.println();
pw.println(" mInteractiveMapper=");
- mInteractiveModeBrightnessMapper.dump(pw, mHbmController.getNormalBrightnessMax());
+ mInteractiveModeBrightnessMapper.dump(pw,
+ mBrightnessRangeController.getNormalBrightnessMax());
if (mIdleModeBrightnessMapper != null) {
pw.println(" mIdleMapper=");
- mIdleModeBrightnessMapper.dump(pw, mHbmController.getNormalBrightnessMax());
+ mIdleModeBrightnessMapper.dump(pw, mBrightnessRangeController.getNormalBrightnessMax());
}
pw.println();
@@ -736,7 +739,7 @@
mAmbientDarkeningThreshold =
mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
}
- mHbmController.onAmbientLuxChange(mAmbientLux);
+ mBrightnessRangeController.onAmbientLuxChange(mAmbientLux);
// If the short term model was invalidated and the change is drastic enough, reset it.
@@ -976,9 +979,9 @@
// Clamps values with float range [0.0-1.0]
private float clampScreenBrightness(float value) {
- final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+ final float minBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMin(),
mBrightnessThrottler.getBrightnessCap());
- final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+ final float maxBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMax(),
mBrightnessThrottler.getBrightnessCap());
return MathUtils.constrain(value, minBrightness, maxBrightness);
}
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java
new file mode 100644
index 0000000..12813c8
--- /dev/null
+++ b/services/core/java/com/android/server/display/BrightnessRangeController.java
@@ -0,0 +1,112 @@
+/*
+ * 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 android.hardware.display.BrightnessInfo;
+import android.os.IBinder;
+
+import java.io.PrintWriter;
+
+class BrightnessRangeController {
+
+ private static final boolean NBM_FEATURE_FLAG = false;
+
+ private final HighBrightnessModeController mHbmController;
+ private final NormalBrightnessModeController mNormalBrightnessModeController =
+ new NormalBrightnessModeController();
+
+ private final Runnable mModeChangeCallback;
+
+ BrightnessRangeController(HighBrightnessModeController hbmController,
+ Runnable modeChangeCallback) {
+ mHbmController = hbmController;
+ mModeChangeCallback = modeChangeCallback;
+ }
+
+
+ void dump(PrintWriter pw) {
+ mHbmController.dump(pw);
+ }
+
+ void onAmbientLuxChange(float ambientLux) {
+ if (NBM_FEATURE_FLAG) {
+ boolean nbmTransitionChanged = mNormalBrightnessModeController.onAmbientLuxChange(
+ ambientLux);
+ int previousHbm = mHbmController.getHighBrightnessMode();
+ mHbmController.onAmbientLuxChange(ambientLux);
+ int nextHbm = mHbmController.getHighBrightnessMode();
+ // if hbm changed - callback was triggered in mHbmController.onAmbientLuxChange
+ // if nbm transition not changed - no need to trigger callback
+ if (previousHbm == nextHbm && nbmTransitionChanged) {
+ mModeChangeCallback.run();
+ }
+ } else {
+ mHbmController.onAmbientLuxChange(ambientLux);
+ }
+ }
+
+ float getNormalBrightnessMax() {
+ return mHbmController.getNormalBrightnessMax();
+ }
+
+ void loadFromConfig(HighBrightnessModeMetadata hbmMetadata, IBinder token,
+ DisplayDeviceInfo info, DisplayDeviceConfig displayDeviceConfig) {
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
+ mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
+ displayDeviceConfig.getHighBrightnessModeData(),
+ displayDeviceConfig::getHdrBrightnessFromSdr);
+ }
+
+ void stop() {
+ mHbmController.stop();
+ }
+
+ void setAutoBrightnessEnabled(int state) {
+ mHbmController.setAutoBrightnessEnabled(state);
+ }
+
+ void onBrightnessChanged(float brightness, float unthrottledBrightness,
+ @BrightnessInfo.BrightnessMaxReason int throttlingReason) {
+ mHbmController.onBrightnessChanged(brightness, unthrottledBrightness, throttlingReason);
+ }
+
+ float getCurrentBrightnessMin() {
+ return mHbmController.getCurrentBrightnessMin();
+ }
+
+
+ float getCurrentBrightnessMax() {
+ if (NBM_FEATURE_FLAG && mHbmController.getHighBrightnessMode()
+ == BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF) {
+ return Math.min(mHbmController.getCurrentBrightnessMax(),
+ mNormalBrightnessModeController.getCurrentBrightnessMax());
+ }
+ return mHbmController.getCurrentBrightnessMax();
+ }
+
+ int getHighBrightnessMode() {
+ return mHbmController.getHighBrightnessMode();
+ }
+
+ float getHdrBrightnessValue() {
+ return mHbmController.getHdrBrightnessValue();
+ }
+
+ float getTransitionPoint() {
+ return mHbmController.getTransitionPoint();
+ }
+}
diff --git a/services/core/java/com/android/server/display/BrightnessSetting.java b/services/core/java/com/android/server/display/BrightnessSetting.java
index de42370..651828b 100644
--- a/services/core/java/com/android/server/display/BrightnessSetting.java
+++ b/services/core/java/com/android/server/display/BrightnessSetting.java
@@ -40,6 +40,7 @@
private final LogicalDisplay mLogicalDisplay;
+ private int mUserSerial;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
@@ -56,13 +57,15 @@
@GuardedBy("mSyncRoot")
private float mBrightness;
- BrightnessSetting(@NonNull PersistentDataStore persistentDataStore,
+ BrightnessSetting(int userSerial,
+ @NonNull PersistentDataStore persistentDataStore,
@NonNull LogicalDisplay logicalDisplay,
DisplayManagerService.SyncRoot syncRoot) {
mPersistentDataStore = persistentDataStore;
mLogicalDisplay = logicalDisplay;
+ mUserSerial = userSerial;
mBrightness = mPersistentDataStore.getBrightness(
- mLogicalDisplay.getPrimaryDisplayDeviceLocked());
+ mLogicalDisplay.getPrimaryDisplayDeviceLocked(), userSerial);
mSyncRoot = syncRoot;
}
@@ -96,8 +99,13 @@
mListeners.remove(l);
}
+ /** Sets the user serial for the brightness setting */
+ public void setUserSerial(int userSerial) {
+ mUserSerial = userSerial;
+ }
+
/**
- * Sets the brigtness and broadcasts the change to the listeners.
+ * Sets the brightness and broadcasts the change to the listeners.
* @param brightness The value to which the brightness is to be set.
*/
public void setBrightness(float brightness) {
@@ -112,7 +120,8 @@
// changed.
if (brightness != mBrightness) {
mPersistentDataStore.setBrightness(mLogicalDisplay.getPrimaryDisplayDeviceLocked(),
- brightness);
+ brightness, mUserSerial
+ );
}
mBrightness = brightness;
int toSend = Float.floatToIntBits(mBrightness);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 3844529..be65c53 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -652,6 +652,12 @@
logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(),
userSerial);
dpc.setBrightnessConfiguration(config, /* shouldResetShortTermModel= */ true);
+ // change the brightness value according to the selected user.
+ final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked();
+ if (device != null) {
+ dpc.setBrightness(
+ mPersistentDataStore.getBrightness(device, userSerial), userSerial);
+ }
}
dpc.onSwitchUser(newUserId);
});
@@ -3134,8 +3140,9 @@
mBrightnessTracker = new BrightnessTracker(mContext, null);
}
- final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore,
- display, mSyncRoot);
+ final int userSerial = getUserManager().getUserSerialNumber(mContext.getUserId());
+ final BrightnessSetting brightnessSetting = new BrightnessSetting(userSerial,
+ mPersistentDataStore, display, mSyncRoot);
final DisplayPowerControllerInterface displayPowerController;
// If display is internal and has a HighBrightnessModeMetadata mapping, use that.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9d31572..7d8bde9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -445,7 +445,7 @@
private final ColorDisplayServiceInternal mCdsi;
private float[] mNitsRange;
- private final HighBrightnessModeController mHbmController;
+ private final BrightnessRangeController mBrightnessRangeController;
private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
private final BrightnessThrottler mBrightnessThrottler;
@@ -654,8 +654,19 @@
loadBrightnessRampRates();
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
+ Runnable modeChangeCallback = () -> {
+ sendUpdatePowerState();
+ postBrightnessChangeRunnable();
+ // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.update();
+ }
+ };
- mHbmController = createHbmControllerLocked();
+ HighBrightnessModeController hbmController = createHbmControllerLocked(modeChangeCallback);
+
+ mBrightnessRangeController = new BrightnessRangeController(hbmController,
+ modeChangeCallback);
mBrightnessThrottler = createBrightnessThrottlerLocked();
@@ -802,7 +813,7 @@
@Override
public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) {
- mHbmController.onAmbientLuxChange(ambientLux);
+ mBrightnessRangeController.onAmbientLuxChange(ambientLux);
if (nits < 0) {
mBrightnessToFollow = leadDisplayBrightness;
} else {
@@ -1039,17 +1050,7 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
- mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
- mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
- mDisplayDeviceConfig.getHighBrightnessModeData(),
- new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
- @Override
- public float getHdrBrightnessFromSdr(
- float sdrBrightness, float maxDesiredHdrSdrRatio) {
- return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
- sdrBrightness, maxDesiredHdrSdrRatio);
- }
- });
+ mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig);
mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(
mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(),
mThermalBrightnessThrottlingDataId, mUniqueDisplayId);
@@ -1264,7 +1265,7 @@
darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
ambientBrightnessThresholds, screenBrightnessThresholds,
ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
- mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
+ mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper,
mDisplayDeviceConfig.getAmbientHorizonShort(),
mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness);
@@ -1364,7 +1365,7 @@
/** Clean up all resources that are accessed via the {@link #mHandler} thread. */
private void cleanupHandlerThreadAfterStop() {
setProximitySensorEnabled(false);
- mHbmController.stop();
+ mBrightnessRangeController.stop();
mBrightnessThrottler.stop();
mHandler.removeCallbacksAndMessages(null);
@@ -1647,7 +1648,7 @@
mShouldResetShortTermModel);
mShouldResetShortTermModel = false;
}
- mHbmController.setAutoBrightnessEnabled(mUseAutoBrightness
+ mBrightnessRangeController.setAutoBrightnessEnabled(mUseAutoBrightness
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
: AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
@@ -1820,7 +1821,7 @@
// here instead of having HbmController listen to the brightness setting because certain
// brightness sources (such as an app override) are not saved to the setting, but should be
// reflected in HBM calculations.
- mHbmController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
+ mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
mBrightnessThrottler.getBrightnessMaxReason());
// Animate the screen brightness when the screen is on or dozing.
@@ -1874,13 +1875,14 @@
float sdrAnimateValue = animateValue;
// TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
// done in HighBrightnessModeController.
- if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ if (mBrightnessRangeController.getHighBrightnessMode()
+ == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
== 0) {
// We want to scale HDR brightness level with the SDR level, we also need to restore
// SDR brightness immediately when entering dim or low power mode.
- animateValue = mHbmController.getHdrBrightnessValue();
+ animateValue = mBrightnessRangeController.getHdrBrightnessValue();
}
final float currentBrightness = mPowerState.getScreenBrightness();
@@ -1942,8 +1944,8 @@
mTempBrightnessEvent.setBrightness(brightnessState);
mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId);
mTempBrightnessEvent.setReason(mBrightnessReason);
- mTempBrightnessEvent.setHbmMax(mHbmController.getCurrentBrightnessMax());
- mTempBrightnessEvent.setHbmMode(mHbmController.getHighBrightnessMode());
+ mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax());
+ mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode());
mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
| (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0)
| (mPowerRequest.lowPowerMode ? BrightnessEvent.FLAG_LOW_POWER_MODE : 0));
@@ -2104,9 +2106,11 @@
private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
synchronized (mCachedBrightnessInfo) {
- final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+ final float minBrightness = Math.min(
+ mBrightnessRangeController.getCurrentBrightnessMin(),
mBrightnessThrottler.getBrightnessCap());
- final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+ final float maxBrightness = Math.min(
+ mBrightnessRangeController.getCurrentBrightnessMax(),
mBrightnessThrottler.getBrightnessCap());
boolean changed = false;
@@ -2124,10 +2128,10 @@
maxBrightness);
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
- mHbmController.getHighBrightnessMode());
+ mBrightnessRangeController.getHighBrightnessMode());
changed |=
mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
- mHbmController.getTransitionPoint());
+ mBrightnessRangeController.getTransitionPoint());
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason,
mBrightnessThrottler.getBrightnessMaxReason());
@@ -2140,7 +2144,8 @@
mHandler.post(mOnBrightnessChangeRunnable);
}
- private HighBrightnessModeController createHbmControllerLocked() {
+ private HighBrightnessModeController createHbmControllerLocked(
+ Runnable modeChangeCallback) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
final IBinder displayToken =
@@ -2159,15 +2164,7 @@
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
sdrBrightness, maxDesiredHdrSdrRatio);
}
- },
- () -> {
- sendUpdatePowerState();
- postBrightnessChangeRunnable();
- // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
- if (mAutomaticBrightnessController != null) {
- mAutomaticBrightnessController.update();
- }
- }, mHighBrightnessModeMetadata, mContext);
+ }, modeChangeCallback, mHighBrightnessModeMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
@@ -2328,8 +2325,8 @@
if (Float.isNaN(value)) {
value = PowerManager.BRIGHTNESS_MIN;
}
- return MathUtils.constrain(value,
- mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
+ return MathUtils.constrain(value, mBrightnessRangeController.getCurrentBrightnessMin(),
+ mBrightnessRangeController.getCurrentBrightnessMax());
}
// Checks whether the brightness is within the valid brightness range, not including off.
@@ -2667,9 +2664,10 @@
}
@Override
- public void setBrightness(float brightnessValue) {
+ public void setBrightness(float brightnessValue, int userSerial) {
// Update the setting, which will eventually call back into DPC to have us actually update
// the display with the new value.
+ mBrightnessSetting.setUserSerial(userSerial);
mBrightnessSetting.setBrightness(brightnessValue);
if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) {
float nits = convertToNits(brightnessValue);
@@ -3003,8 +3001,8 @@
mScreenOffBrightnessSensorController.dump(pw);
}
- if (mHbmController != null) {
- mHbmController.dump(pw);
+ if (mBrightnessRangeController != null) {
+ mBrightnessRangeController.dump(pw);
}
if (mBrightnessThrottler != null) {
@@ -3471,7 +3469,8 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
+ BrightnessRangeController brightnessRangeController,
+ BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong, float userLux, float userBrightness) {
return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor,
@@ -3480,9 +3479,9 @@
brighteningLightDebounceConfig, darkeningLightDebounceConfig,
resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds,
screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
- screenBrightnessThresholdsIdle, context, hbmController, brightnessThrottler,
- idleModeBrightnessMapper, ambientLightHorizonShort, ambientLightHorizonLong,
- userLux, userBrightness);
+ screenBrightnessThresholdsIdle, context, brightnessRangeController,
+ brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort,
+ ambientLightHorizonLong, userLux, userBrightness);
}
BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 41e4671d..040cecc 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -376,8 +376,7 @@
private final ColorDisplayServiceInternal mCdsi;
private float[] mNitsRange;
- private final HighBrightnessModeController mHbmController;
- private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
+ private final BrightnessRangeController mBrightnessRangeController;
private final BrightnessThrottler mBrightnessThrottler;
@@ -489,7 +488,6 @@
mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
() -> updatePowerState(), mDisplayId, mSensorManager);
- mHighBrightnessModeMetadata = hbmMetadata;
mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController);
mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId);
mTag = "DisplayPowerController2[" + mDisplayId + "]";
@@ -532,9 +530,22 @@
mSkipScreenOnBrightnessRamp = resources.getBoolean(
R.bool.config_skipScreenOnBrightnessRamp);
- mHbmController = createHbmControllerLocked();
+ Runnable modeChangeCallback = () -> {
+ sendUpdatePowerState();
+ postBrightnessChangeRunnable();
+ // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.update();
+ }
+ };
+ HighBrightnessModeController hbmController = createHbmControllerLocked(hbmMetadata,
+ modeChangeCallback);
mBrightnessThrottler = createBrightnessThrottlerLocked();
+
+ mBrightnessRangeController = new BrightnessRangeController(hbmController,
+ modeChangeCallback);
+
mDisplayBrightnessController =
new DisplayBrightnessController(context, null,
mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault,
@@ -848,17 +859,8 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
- mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
- mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
- mDisplayDeviceConfig.getHighBrightnessModeData(),
- new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
- @Override
- public float getHdrBrightnessFromSdr(
- float sdrBrightness, float maxDesiredHdrSdrRatio) {
- return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
- sdrBrightness, maxDesiredHdrSdrRatio);
- }
- });
+
+ mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig);
mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(
mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(),
mThermalBrightnessThrottlingDataId, mUniqueDisplayId);
@@ -1076,7 +1078,7 @@
darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
ambientBrightnessThresholds, screenBrightnessThresholds,
ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
- mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
+ mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper,
mDisplayDeviceConfig.getAmbientHorizonShort(),
mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness);
mDisplayBrightnessController.setAutomaticBrightnessController(
@@ -1180,7 +1182,7 @@
/** Clean up all resources that are accessed via the {@link #mHandler} thread. */
private void cleanupHandlerThreadAfterStop() {
mDisplayPowerProximityStateController.cleanup();
- mHbmController.stop();
+ mBrightnessRangeController.stop();
mBrightnessThrottler.stop();
mHandler.removeCallbacksAndMessages(null);
@@ -1295,7 +1297,7 @@
&& (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()
|| userSetBrightnessChanged);
- mHbmController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy
+ mBrightnessRangeController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy
.shouldUseAutoBrightness()
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
: AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
@@ -1452,7 +1454,7 @@
// here instead of having HbmController listen to the brightness setting because certain
// brightness sources (such as an app override) are not saved to the setting, but should be
// reflected in HBM calculations.
- mHbmController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
+ mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
mBrightnessThrottler.getBrightnessMaxReason());
// Animate the screen brightness when the screen is on or dozing.
@@ -1509,13 +1511,14 @@
float sdrAnimateValue = animateValue;
// TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
// done in HighBrightnessModeController.
- if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ if (mBrightnessRangeController.getHighBrightnessMode()
+ == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
== 0) {
// We want to scale HDR brightness level with the SDR level, we also need to restore
// SDR brightness immediately when entering dim or low power mode.
- animateValue = mHbmController.getHdrBrightnessValue();
+ animateValue = mBrightnessRangeController.getHdrBrightnessValue();
}
final float currentBrightness = mPowerState.getScreenBrightness();
@@ -1579,8 +1582,8 @@
mTempBrightnessEvent.setBrightness(brightnessState);
mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId);
mTempBrightnessEvent.setReason(mBrightnessReason);
- mTempBrightnessEvent.setHbmMax(mHbmController.getCurrentBrightnessMax());
- mTempBrightnessEvent.setHbmMode(mHbmController.getHighBrightnessMode());
+ mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax());
+ mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode());
mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
| (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0)
| (mPowerRequest.lowPowerMode ? BrightnessEvent.FLAG_LOW_POWER_MODE : 0));
@@ -1750,9 +1753,11 @@
private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
synchronized (mCachedBrightnessInfo) {
- final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+ final float minBrightness = Math.min(
+ mBrightnessRangeController.getCurrentBrightnessMin(),
mBrightnessThrottler.getBrightnessCap());
- final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+ final float maxBrightness = Math.min(
+ mBrightnessRangeController.getCurrentBrightnessMax(),
mBrightnessThrottler.getBrightnessCap());
boolean changed = false;
@@ -1770,10 +1775,10 @@
maxBrightness);
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
- mHbmController.getHighBrightnessMode());
+ mBrightnessRangeController.getHighBrightnessMode());
changed |=
mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
- mHbmController.getTransitionPoint());
+ mBrightnessRangeController.getTransitionPoint());
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason,
mBrightnessThrottler.getBrightnessMaxReason());
@@ -1786,7 +1791,8 @@
mHandler.post(mOnBrightnessChangeRunnable);
}
- private HighBrightnessModeController createHbmControllerLocked() {
+ private HighBrightnessModeController createHbmControllerLocked(
+ HighBrightnessModeMetadata hbmMetadata, Runnable modeChangeCallback) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
final IBinder displayToken =
@@ -1798,22 +1804,9 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
- new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
- @Override
- public float getHdrBrightnessFromSdr(
- float sdrBrightness, float maxDesiredHdrSdrRatio) {
- return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
- sdrBrightness, maxDesiredHdrSdrRatio);
- }
- },
- () -> {
- sendUpdatePowerState();
- postBrightnessChangeRunnable();
- // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
- if (mAutomaticBrightnessController != null) {
- mAutomaticBrightnessController.update();
- }
- }, mHighBrightnessModeMetadata, mContext);
+ (sdrBrightness, maxDesiredHdrSdrRatio) ->
+ mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness,
+ maxDesiredHdrSdrRatio), modeChangeCallback, hbmMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
@@ -1960,8 +1953,8 @@
if (Float.isNaN(value)) {
value = PowerManager.BRIGHTNESS_MIN;
}
- return MathUtils.constrain(value,
- mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
+ return MathUtils.constrain(value, mBrightnessRangeController.getCurrentBrightnessMin(),
+ mBrightnessRangeController.getCurrentBrightnessMax());
}
private void animateScreenBrightness(float target, float sdrTarget, float rate) {
@@ -2179,8 +2172,8 @@
}
@Override
- public void setBrightness(float brightnessValue) {
- mDisplayBrightnessController.setBrightness(brightnessValue);
+ public void setBrightness(float brightnessValue, int userSerial) {
+ mDisplayBrightnessController.setBrightness(brightnessValue, userSerial);
}
@Override
@@ -2195,7 +2188,7 @@
@Override
public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) {
- mHbmController.onAmbientLuxChange(ambientLux);
+ mBrightnessRangeController.onAmbientLuxChange(ambientLux);
if (nits < 0) {
mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness);
} else {
@@ -2374,8 +2367,8 @@
dumpRbcEvents(pw);
- if (mHbmController != null) {
- mHbmController.dump(pw);
+ if (mBrightnessRangeController != null) {
+ mBrightnessRangeController.dump(pw);
}
if (mBrightnessThrottler != null) {
@@ -2840,7 +2833,8 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
+ BrightnessRangeController brightnessModeController,
+ BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong, float userLux, float userBrightness) {
return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor,
@@ -2849,9 +2843,9 @@
brighteningLightDebounceConfig, darkeningLightDebounceConfig,
resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds,
screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
- screenBrightnessThresholdsIdle, context, hbmController, brightnessThrottler,
- idleModeBrightnessMapper, ambientLightHorizonShort, ambientLightHorizonLong,
- userLux, userBrightness);
+ screenBrightnessThresholdsIdle, context, brightnessModeController,
+ brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort,
+ ambientLightHorizonLong, userLux, userBrightness);
}
BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index 73edb97..5fbbcbd 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -29,7 +29,7 @@
* An interface to manage the display's power state and brightness
*/
public interface DisplayPowerControllerInterface {
-
+ int DEFAULT_USER_SERIAL = -1;
/**
* Notified when the display is changed.
*
@@ -98,7 +98,17 @@
* Set the screen brightness of the associated display
* @param brightness The value to which the brightness is to be set
*/
- void setBrightness(float brightness);
+ default void setBrightness(float brightness) {
+ setBrightness(brightness, DEFAULT_USER_SERIAL);
+ }
+
+ /**
+ * Set the screen brightness of the associated display
+ * @param brightness The value to which the brightness is to be set
+ * @param userSerial The user for which the brightness value is to be set. Use userSerial = -1,
+ * if brightness needs to be updated for the current user.
+ */
+ void setBrightness(float brightness, int userSerial);
/**
* Checks if the proximity sensor is available
diff --git a/services/core/java/com/android/server/display/NormalBrightnessModeController.java b/services/core/java/com/android/server/display/NormalBrightnessModeController.java
new file mode 100644
index 0000000..91e4a9e
--- /dev/null
+++ b/services/core/java/com/android/server/display/NormalBrightnessModeController.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.os.PowerManager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class NormalBrightnessModeController {
+ private Map<Float, Float> mTransitionPoints = new HashMap<>();
+
+ // brightness limit in normal brightness mode, based on ambient lux.
+ private float mVirtualTransitionPoint = PowerManager.BRIGHTNESS_MAX;
+
+ boolean onAmbientLuxChange(float ambientLux) {
+ float currentAmbientBoundary = Float.MAX_VALUE;
+ float currentTransitionPoint = PowerManager.BRIGHTNESS_MAX;
+ for (Map.Entry<Float, Float> transitionPoint: mTransitionPoints.entrySet()) {
+ float ambientBoundary = transitionPoint.getKey();
+ // find ambient lux upper boundary closest to current ambient lux
+ if (ambientBoundary > ambientLux && ambientBoundary < currentAmbientBoundary) {
+ currentTransitionPoint = transitionPoint.getValue();
+ currentAmbientBoundary = ambientBoundary;
+ }
+ }
+ if (mVirtualTransitionPoint != currentTransitionPoint) {
+ mVirtualTransitionPoint = currentTransitionPoint;
+ return true;
+ }
+ return false;
+ }
+
+ float getCurrentBrightnessMax() {
+ return mVirtualTransitionPoint;
+ }
+}
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 6d6ed72..2d7792d 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -133,6 +133,7 @@
private static final String TAG_BRIGHTNESS_NITS_FOR_DEFAULT_DISPLAY =
"brightness-nits-for-default-display";
+ public static final int DEFAULT_USER_ID = -1;
// Remembered Wifi display devices.
private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
@@ -294,7 +295,7 @@
return false;
}
- public float getBrightness(DisplayDevice device) {
+ public float getBrightness(DisplayDevice device, int userSerial) {
if (device == null || !device.hasStableUniqueId()) {
return Float.NaN;
}
@@ -302,10 +303,10 @@
if (state == null) {
return Float.NaN;
}
- return state.getBrightness();
+ return state.getBrightness(userSerial);
}
- public boolean setBrightness(DisplayDevice displayDevice, float brightness) {
+ public boolean setBrightness(DisplayDevice displayDevice, float brightness, int userSerial) {
if (displayDevice == null || !displayDevice.hasStableUniqueId()) {
return false;
}
@@ -314,7 +315,7 @@
return false;
}
final DisplayState state = getDisplayState(displayDeviceUniqueId, true);
- if (state.setBrightness(brightness)) {
+ if (state.setBrightness(brightness, userSerial)) {
setDirty();
return true;
}
@@ -611,6 +612,7 @@
state.saveToXml(serializer);
serializer.endTag(null, TAG_DISPLAY);
}
+
serializer.endTag(null, TAG_DISPLAY_STATES);
serializer.startTag(null, TAG_STABLE_DEVICE_VALUES);
mStableDeviceValues.saveToXml(serializer);
@@ -649,7 +651,8 @@
private static final class DisplayState {
private int mColorMode;
- private float mBrightness = Float.NaN;
+
+ private SparseArray<Float> mPerUserBrightness = new SparseArray<>();
private int mWidth;
private int mHeight;
private float mRefreshRate;
@@ -670,16 +673,25 @@
return mColorMode;
}
- public boolean setBrightness(float brightness) {
- if (brightness == mBrightness) {
+ public boolean setBrightness(float brightness, int userSerial) {
+ // Remove the default user brightness, before setting a new user-specific value.
+ // This is a one-time operation, required to restructure the config after user-specific
+ // brightness was introduced.
+ mPerUserBrightness.remove(DEFAULT_USER_ID);
+
+ if (getBrightness(userSerial) == brightness) {
return false;
}
- mBrightness = brightness;
+ mPerUserBrightness.set(userSerial, brightness);
return true;
}
- public float getBrightness() {
- return mBrightness;
+ public float getBrightness(int userSerial) {
+ float brightness = mPerUserBrightness.get(userSerial, Float.NaN);
+ if (Float.isNaN(brightness)) {
+ brightness = mPerUserBrightness.get(DEFAULT_USER_ID, Float.NaN);
+ }
+ return brightness;
}
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration,
@@ -729,12 +741,7 @@
mColorMode = Integer.parseInt(value);
break;
case TAG_BRIGHTNESS_VALUE:
- String brightness = parser.nextText();
- try {
- mBrightness = Float.parseFloat(brightness);
- } catch (NumberFormatException e) {
- mBrightness = Float.NaN;
- }
+ loadBrightnessFromXml(parser);
break;
case TAG_BRIGHTNESS_CONFIGURATIONS:
mDisplayBrightnessConfigurations.loadFromXml(parser);
@@ -760,11 +767,12 @@
serializer.text(Integer.toString(mColorMode));
serializer.endTag(null, TAG_COLOR_MODE);
- serializer.startTag(null, TAG_BRIGHTNESS_VALUE);
- if (!Float.isNaN(mBrightness)) {
- serializer.text(Float.toString(mBrightness));
+ for (int i = 0; i < mPerUserBrightness.size(); i++) {
+ serializer.startTag(null, TAG_BRIGHTNESS_VALUE);
+ serializer.attributeInt(null, ATTR_USER_SERIAL, mPerUserBrightness.keyAt(i));
+ serializer.text(Float.toString(mPerUserBrightness.valueAt(i)));
+ serializer.endTag(null, TAG_BRIGHTNESS_VALUE);
}
- serializer.endTag(null, TAG_BRIGHTNESS_VALUE);
serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
mDisplayBrightnessConfigurations.saveToXml(serializer);
@@ -785,12 +793,33 @@
public void dump(final PrintWriter pw, final String prefix) {
pw.println(prefix + "ColorMode=" + mColorMode);
- pw.println(prefix + "BrightnessValue=" + mBrightness);
+ pw.println(prefix + "BrightnessValues: ");
+ for (int i = 0; i < mPerUserBrightness.size(); i++) {
+ pw.println("User: " + mPerUserBrightness.keyAt(i)
+ + " Value: " + mPerUserBrightness.valueAt(i));
+ }
pw.println(prefix + "DisplayBrightnessConfigurations: ");
mDisplayBrightnessConfigurations.dump(pw, prefix);
pw.println(prefix + "Resolution=" + mWidth + " " + mHeight);
pw.println(prefix + "RefreshRate=" + mRefreshRate);
}
+
+ private void loadBrightnessFromXml(TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int userSerial;
+ try {
+ userSerial = parser.getAttributeInt(null, ATTR_USER_SERIAL);
+ } catch (NumberFormatException | XmlPullParserException e) {
+ userSerial = DEFAULT_USER_ID;
+ Slog.e(TAG, "Failed to read user serial", e);
+ }
+ String brightness = parser.nextText();
+ try {
+ mPerUserBrightness.set(userSerial, Float.parseFloat(brightness));
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, "Failed to read brightness", nfe);
+ }
+ }
}
private static final class StableDeviceValues {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 7574de8..2f52b70 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -38,6 +38,8 @@
* display. Applies the chosen brightness.
*/
public final class DisplayBrightnessController {
+ private static final int DEFAULT_USER_SERIAL = -1;
+
// The ID of the display tied to this DisplayBrightnessController
private final int mDisplayId;
@@ -274,8 +276,16 @@
* Notifies the brightnessSetting to persist the supplied brightness value.
*/
public void setBrightness(float brightnessValue) {
+ setBrightness(brightnessValue, DEFAULT_USER_SERIAL);
+ }
+
+ /**
+ * Notifies the brightnessSetting to persist the supplied brightness value for a user.
+ */
+ public void setBrightness(float brightnessValue, int userSerial) {
// Update the setting, which will eventually call back into DPC to have us actually
// update the display with the new value.
+ mBrightnessSetting.setUserSerial(userSerial);
mBrightnessSetting.setBrightness(brightnessValue);
if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) {
float nits = convertToNits(brightnessValue);
diff --git a/services/core/java/com/android/server/input/InputFeatureFlagProvider.java b/services/core/java/com/android/server/input/InputFeatureFlagProvider.java
new file mode 100644
index 0000000..7c7f151
--- /dev/null
+++ b/services/core/java/com/android/server/input/InputFeatureFlagProvider.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import android.sysprop.InputProperties;
+
+import java.util.Optional;
+
+/**
+ * A component of {@link InputManagerService} responsible for managing the input sysprop flags
+ *
+ * @hide
+ */
+@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+public final class InputFeatureFlagProvider {
+
+ // To disable Keyboard backlight control via Framework, run:
+ // 'adb shell setprop persist.input.keyboard_backlight_control.enabled false' (requires restart)
+ private static final boolean KEYBOARD_BACKLIGHT_CONTROL_ENABLED =
+ InputProperties.enable_keyboard_backlight_control().orElse(true);
+
+ // To disable Framework controlled keyboard backlight animation run:
+ // adb shell setprop persist.input.keyboard.backlight_animation.enabled false (requires restart)
+ private static final boolean KEYBOARD_BACKLIGHT_ANIMATION_ENABLED =
+ InputProperties.enable_keyboard_backlight_animation().orElse(false);
+
+ // To disable Custom keyboard backlight levels support via IDC files run:
+ // adb shell setprop persist.input.keyboard_backlight_custom_levels.enabled false (requires
+ // restart)
+ private static final boolean KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED =
+ InputProperties.enable_keyboard_backlight_custom_levels().orElse(true);
+
+ private static Optional<Boolean> sKeyboardBacklightControlOverride = Optional.empty();
+ private static Optional<Boolean> sKeyboardBacklightAnimationOverride = Optional.empty();
+ private static Optional<Boolean> sKeyboardBacklightCustomLevelsOverride = Optional.empty();
+
+ public static boolean isKeyboardBacklightControlEnabled() {
+ return sKeyboardBacklightControlOverride.orElse(KEYBOARD_BACKLIGHT_CONTROL_ENABLED);
+ }
+
+ public static boolean isKeyboardBacklightAnimationEnabled() {
+ return sKeyboardBacklightAnimationOverride.orElse(KEYBOARD_BACKLIGHT_ANIMATION_ENABLED);
+ }
+
+ public static boolean isKeyboardBacklightCustomLevelsEnabled() {
+ return sKeyboardBacklightCustomLevelsOverride.orElse(
+ KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED);
+ }
+
+ public static void setKeyboardBacklightControlEnabled(boolean enabled) {
+ sKeyboardBacklightControlOverride = Optional.of(enabled);
+ }
+
+ public static void setKeyboardBacklightAnimationEnabled(boolean enabled) {
+ sKeyboardBacklightAnimationOverride = Optional.of(enabled);
+ }
+
+ public static void setKeyboardBacklightCustomLevelsEnabled(boolean enabled) {
+ sKeyboardBacklightCustomLevelsOverride = Optional.of(enabled);
+ }
+
+ /**
+ * Clears all input feature flag overrides.
+ */
+ public static void clearOverrides() {
+ sKeyboardBacklightControlOverride = Optional.empty();
+ sKeyboardBacklightAnimationOverride = Optional.empty();
+ sKeyboardBacklightCustomLevelsOverride = Optional.empty();
+ }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 4cb22db..c7b80af 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -74,7 +74,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.vibrator.StepSegment;
@@ -160,11 +159,6 @@
private static final AdditionalDisplayInputProperties
DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties();
- // To disable Keyboard backlight control via Framework, run:
- // 'adb shell setprop persist.input.keyboard_backlight_control.enabled false' (requires restart)
- private static final boolean KEYBOARD_BACKLIGHT_CONTROL_ENABLED = SystemProperties.getBoolean(
- "persist.input.keyboard.backlight_control.enabled", true);
-
private final NativeInputManagerService mNative;
private final Context mContext;
@@ -439,10 +433,9 @@
mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore,
injector.getLooper());
mBatteryController = new BatteryController(mContext, mNative, injector.getLooper());
- mKeyboardBacklightController =
- KEYBOARD_BACKLIGHT_CONTROL_ENABLED ? new KeyboardBacklightController(mContext,
- mNative, mDataStore, injector.getLooper())
- : new KeyboardBacklightControllerInterface() {};
+ mKeyboardBacklightController = InputFeatureFlagProvider.isKeyboardBacklightControlEnabled()
+ ? new KeyboardBacklightController(mContext, mNative, mDataStore,
+ injector.getLooper()) : new KeyboardBacklightControllerInterface() {};
mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
mUseDevInputEventForAudioJack =
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 651063e..42591f4 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -115,35 +115,34 @@
return setting != 0;
}
- private int getPointerSpeedValue(String settingName) {
- int speed = Settings.System.getIntForUser(mContext.getContentResolver(),
- settingName, InputSettings.DEFAULT_POINTER_SPEED, UserHandle.USER_CURRENT);
+ private int constrainPointerSpeedValue(int speed) {
return Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
InputSettings.MAX_POINTER_SPEED);
}
private void updateMousePointerSpeed() {
- mNative.setPointerSpeed(getPointerSpeedValue(Settings.System.POINTER_SPEED));
+ int speed = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED, InputSettings.DEFAULT_POINTER_SPEED,
+ UserHandle.USER_CURRENT);
+ mNative.setPointerSpeed(constrainPointerSpeedValue(speed));
}
private void updateTouchpadPointerSpeed() {
mNative.setTouchpadPointerSpeed(
- getPointerSpeedValue(Settings.System.TOUCHPAD_POINTER_SPEED));
+ constrainPointerSpeedValue(InputSettings.getTouchpadPointerSpeed(mContext)));
}
private void updateTouchpadNaturalScrollingEnabled() {
mNative.setTouchpadNaturalScrollingEnabled(
- getBoolean(Settings.System.TOUCHPAD_NATURAL_SCROLLING, true));
+ InputSettings.useTouchpadNaturalScrolling(mContext));
}
private void updateTouchpadTapToClickEnabled() {
- mNative.setTouchpadTapToClickEnabled(
- getBoolean(Settings.System.TOUCHPAD_TAP_TO_CLICK, true));
+ mNative.setTouchpadTapToClickEnabled(InputSettings.useTouchpadTapToClick(mContext));
}
private void updateTouchpadRightClickZoneEnabled() {
- mNative.setTouchpadRightClickZoneEnabled(
- getBoolean(Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, false));
+ mNative.setTouchpadRightClickZoneEnabled(InputSettings.useTouchpadRightClickZone(mContext));
}
private void updateShowTouches() {
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index 48c346a..36238a8 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import android.animation.ValueAnimator;
import android.annotation.BinderThread;
import android.content.Context;
import android.graphics.Color;
@@ -45,6 +46,7 @@
import java.util.Arrays;
import java.util.Objects;
import java.util.OptionalInt;
+import java.util.TreeSet;
/**
* A thread-safe component of {@link InputManagerService} responsible for managing the keyboard
@@ -69,7 +71,11 @@
private static final int MSG_NOTIFY_USER_INACTIVITY = 5;
private static final int MSG_INTERACTIVE_STATE_CHANGED = 6;
private static final int MAX_BRIGHTNESS = 255;
- private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10;
+ private static final int DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS = 10;
+ @VisibleForTesting
+ static final int MAX_BRIGHTNESS_CHANGE_STEPS = 10;
+ private static final long TRANSITION_ANIMATION_DURATION_MILLIS =
+ Duration.ofSeconds(1).toMillis();
private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight";
@@ -77,7 +83,8 @@
static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();
@VisibleForTesting
- static final int[] BRIGHTNESS_VALUE_FOR_LEVEL = new int[NUM_BRIGHTNESS_CHANGE_STEPS + 1];
+ static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL =
+ new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1];
private final Context mContext;
private final NativeInputManagerService mNative;
@@ -85,6 +92,7 @@
@GuardedBy("mDataStore")
private final PersistentDataStore mDataStore;
private final Handler mHandler;
+ private final AnimatorFactory mAnimatorFactory;
// Always access on handler thread or need to lock this for synchronization.
private final SparseArray<KeyboardBacklightState> mKeyboardBacklights = new SparseArray<>(1);
// Maintains state if all backlights should be on or turned off
@@ -100,19 +108,26 @@
static {
// Fixed brightness levels to avoid issues when converting back and forth from the
// device brightness range to [0-255]
- // Levels are: 0, 25, 51, ..., 255
- for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
- BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
- ((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS);
+ // Levels are: 0, 51, ..., 255
+ for (int i = 0; i <= DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
+ ((float) i * MAX_BRIGHTNESS) / DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS);
}
}
KeyboardBacklightController(Context context, NativeInputManagerService nativeService,
PersistentDataStore dataStore, Looper looper) {
+ this(context, nativeService, dataStore, looper, ValueAnimator::ofInt);
+ }
+
+ @VisibleForTesting
+ KeyboardBacklightController(Context context, NativeInputManagerService nativeService,
+ PersistentDataStore dataStore, Looper looper, AnimatorFactory animatorFactory) {
mContext = context;
mNative = nativeService;
mDataStore = dataStore;
mHandler = new Handler(looper, this::handleMessage);
+ mAnimatorFactory = animatorFactory;
}
@Override
@@ -173,18 +188,18 @@
final int currBrightnessLevel = state.mBrightnessLevel;
final int newBrightnessLevel;
if (direction == Direction.DIRECTION_UP) {
- newBrightnessLevel = Math.min(currBrightnessLevel + 1, NUM_BRIGHTNESS_CHANGE_STEPS);
+ newBrightnessLevel = Math.min(currBrightnessLevel + 1,
+ state.getNumBrightnessChangeSteps());
} else {
newBrightnessLevel = Math.max(currBrightnessLevel - 1, 0);
}
- updateBacklightState(deviceId, keyboardBacklight, newBrightnessLevel,
- true /* isTriggeredByKeyPress */);
+ updateBacklightState(deviceId, newBrightnessLevel, true /* isTriggeredByKeyPress */);
synchronized (mDataStore) {
try {
mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(),
keyboardBacklight.getId(),
- BRIGHTNESS_VALUE_FOR_LEVEL[newBrightnessLevel]);
+ state.mBrightnessValueForLevel[newBrightnessLevel]);
} finally {
mDataStore.saveIfNeeded();
}
@@ -192,6 +207,7 @@
}
private void restoreBacklightBrightness(InputDevice inputDevice, Light keyboardBacklight) {
+ KeyboardBacklightState state = mKeyboardBacklights.get(inputDevice.getId());
OptionalInt brightness;
synchronized (mDataStore) {
brightness = mDataStore.getKeyboardBacklightBrightness(
@@ -199,12 +215,11 @@
}
if (brightness.isPresent()) {
int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt()));
- int index = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
+ int index = Arrays.binarySearch(state.mBrightnessValueForLevel, brightnessValue);
if (index < 0) {
- index = Math.min(NUM_BRIGHTNESS_CHANGE_STEPS, -(index + 1));
+ index = Math.min(state.getNumBrightnessChangeSteps(), -(index + 1));
}
- updateBacklightState(inputDevice.getId(), keyboardBacklight, index,
- false /* isTriggeredByKeyPress */);
+ updateBacklightState(inputDevice.getId(), index, false /* isTriggeredByKeyPress */);
if (DEBUG) {
Slog.d(TAG, "Restoring brightness level " + brightness.getAsInt());
}
@@ -217,14 +232,10 @@
if (!mIsInteractive) {
return;
}
- if (!mIsBacklightOn) {
- mIsBacklightOn = true;
- for (int i = 0; i < mKeyboardBacklights.size(); i++) {
- int deviceId = mKeyboardBacklights.keyAt(i);
- KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
- updateBacklightState(deviceId, state.mLight, state.mBrightnessLevel,
- false /* isTriggeredByKeyPress */);
- }
+ mIsBacklightOn = true;
+ for (int i = 0; i < mKeyboardBacklights.size(); i++) {
+ KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
+ state.onBacklightStateChanged();
}
mHandler.removeMessages(MSG_NOTIFY_USER_INACTIVITY);
mHandler.sendEmptyMessageAtTime(MSG_NOTIFY_USER_INACTIVITY,
@@ -232,14 +243,10 @@
}
private void handleUserInactivity() {
- if (mIsBacklightOn) {
- mIsBacklightOn = false;
- for (int i = 0; i < mKeyboardBacklights.size(); i++) {
- int deviceId = mKeyboardBacklights.keyAt(i);
- KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
- updateBacklightState(deviceId, state.mLight, state.mBrightnessLevel,
- false /* isTriggeredByKeyPress */);
- }
+ mIsBacklightOn = false;
+ for (int i = 0; i < mKeyboardBacklights.size(); i++) {
+ KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
+ state.onBacklightStateChanged();
}
}
@@ -310,7 +317,7 @@
return;
}
// The keyboard backlight was added or changed.
- mKeyboardBacklights.put(deviceId, new KeyboardBacklightState(keyboardBacklight));
+ mKeyboardBacklights.put(deviceId, new KeyboardBacklightState(deviceId, keyboardBacklight));
restoreBacklightBrightness(inputDevice, keyboardBacklight);
}
@@ -372,31 +379,28 @@
}
}
- private void updateBacklightState(int deviceId, Light light, int brightnessLevel,
+ private void updateBacklightState(int deviceId, int brightnessLevel,
boolean isTriggeredByKeyPress) {
KeyboardBacklightState state = mKeyboardBacklights.get(deviceId);
if (state == null) {
return;
}
- mNative.setLightColor(deviceId, light.getId(),
- mIsBacklightOn ? Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[brightnessLevel], 0, 0, 0)
- : 0);
- if (DEBUG) {
- Slog.d(TAG, "Changing state from " + state.mBrightnessLevel + " to " + brightnessLevel
- + "(isBacklightOn = " + mIsBacklightOn + ")");
- }
- state.mBrightnessLevel = brightnessLevel;
+ state.setBrightnessLevel(brightnessLevel);
synchronized (mKeyboardBacklightListenerRecords) {
for (int i = 0; i < mKeyboardBacklightListenerRecords.size(); i++) {
IKeyboardBacklightState callbackState = new IKeyboardBacklightState();
callbackState.brightnessLevel = brightnessLevel;
- callbackState.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS;
+ callbackState.maxBrightnessLevel = state.getNumBrightnessChangeSteps();
mKeyboardBacklightListenerRecords.valueAt(i).notifyKeyboardBacklightChanged(
deviceId, callbackState, isTriggeredByKeyPress);
}
}
+
+ if (DEBUG) {
+ Slog.d(TAG, "Changing state from " + state.mBrightnessLevel + " to " + brightnessLevel);
+ }
}
private void onKeyboardBacklightListenerDied(int pid) {
@@ -436,10 +440,7 @@
@Override
public void dump(PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
- ipw.println(
- TAG + ": " + mKeyboardBacklights.size() + " keyboard backlights, isBacklightOn = "
- + mIsBacklightOn);
-
+ ipw.println(TAG + ": " + mKeyboardBacklights.size() + " keyboard backlights");
ipw.increaseIndent();
for (int i = 0; i < mKeyboardBacklights.size(); i++) {
KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
@@ -478,12 +479,87 @@
}
}
- private static class KeyboardBacklightState {
+ private class KeyboardBacklightState {
+ private final int mDeviceId;
private final Light mLight;
private int mBrightnessLevel;
+ private ValueAnimator mAnimator;
+ private final int[] mBrightnessValueForLevel;
- KeyboardBacklightState(Light light) {
+ KeyboardBacklightState(int deviceId, Light light) {
+ mDeviceId = deviceId;
mLight = light;
+ mBrightnessValueForLevel = setupBrightnessLevels();
+ }
+
+ private int[] setupBrightnessLevels() {
+ if (!InputFeatureFlagProvider.isKeyboardBacklightCustomLevelsEnabled()) {
+ return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
+ }
+ int[] customLevels = mLight.getPreferredBrightnessLevels();
+ if (customLevels == null || customLevels.length == 0) {
+ return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
+ }
+ TreeSet<Integer> brightnessLevels = new TreeSet<>();
+ brightnessLevels.add(0);
+ for (int level : customLevels) {
+ if (level > 0 && level < MAX_BRIGHTNESS) {
+ brightnessLevels.add(level);
+ }
+ }
+ brightnessLevels.add(MAX_BRIGHTNESS);
+ int brightnessChangeSteps = brightnessLevels.size() - 1;
+ if (brightnessChangeSteps > MAX_BRIGHTNESS_CHANGE_STEPS) {
+ return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
+ }
+ int[] result = new int[brightnessLevels.size()];
+ int index = 0;
+ for (int val : brightnessLevels) {
+ result[index++] = val;
+ }
+ return result;
+ }
+
+ private int getNumBrightnessChangeSteps() {
+ return mBrightnessValueForLevel.length - 1;
+ }
+
+ private void onBacklightStateChanged() {
+ setBacklightValue(mIsBacklightOn ? mBrightnessValueForLevel[mBrightnessLevel] : 0);
+ }
+ private void setBrightnessLevel(int brightnessLevel) {
+ if (mIsBacklightOn) {
+ setBacklightValue(mBrightnessValueForLevel[brightnessLevel]);
+ }
+ mBrightnessLevel = brightnessLevel;
+ }
+
+ private void cancelAnimation() {
+ if (mAnimator != null && mAnimator.isRunning()) {
+ mAnimator.cancel();
+ }
+ }
+
+ private void setBacklightValue(int toValue) {
+ int fromValue = Color.alpha(mNative.getLightColor(mDeviceId, mLight.getId()));
+ if (fromValue == toValue) {
+ return;
+ }
+ if (InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled()) {
+ startAnimation(fromValue, toValue);
+ } else {
+ mNative.setLightColor(mDeviceId, mLight.getId(), Color.argb(toValue, 0, 0, 0));
+ }
+ }
+
+ private void startAnimation(int fromValue, int toValue) {
+ // Cancel any ongoing animation before starting a new one
+ cancelAnimation();
+ mAnimator = mAnimatorFactory.makeIntAnimator(fromValue, toValue);
+ mAnimator.addUpdateListener(
+ (animation) -> mNative.setLightColor(mDeviceId, mLight.getId(),
+ Color.argb((int) animation.getAnimatedValue(), 0, 0, 0)));
+ mAnimator.setDuration(TRANSITION_ANIMATION_DURATION_MILLIS).start();
}
@Override
@@ -493,4 +569,9 @@
+ "}";
}
}
+
+ @VisibleForTesting
+ interface AnimatorFactory {
+ ValueAnimator makeIntAnimator(int from, int to);
+ }
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 6ec4022..611a61a2 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -252,6 +252,8 @@
if (needToShowNotification) {
maybeUpdateNotification();
}
+ // TODO (b/280421650): Implement logging statements using KeyboardMetricsCollector
+ // for KeyboardConfigured atom
}
private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
new file mode 100644
index 0000000..b8f57f5
--- /dev/null
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.hardware.input.KeyboardLayout;
+import android.util.proto.ProtoOutputStream;
+import android.view.InputDevice;
+
+import com.android.internal.os.KeyboardConfiguredProto.KeyboardLayoutConfig;
+import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.lang.annotation.Retention;
+import java.util.List;
+
+/**
+ * Collect Keyboard metrics
+ */
+public final class KeyboardMetricsCollector {
+ private static final String TAG = "KeyboardMetricCollector";
+
+ /**
+ * Log keyboard system shortcuts for the proto
+ * {@link com.android.os.input.KeyboardSystemsEventReported}
+ * defined in "stats/atoms/input/input_extension_atoms.proto"
+ */
+ public static void logKeyboardSystemsEventReportedAtom(InputDevice inputDevice,
+ int keyboardSystemEvent, int[] keyCode, int modifierState) {
+ int vendor_id = inputDevice.getVendorId();
+ int product_id = inputDevice.getProductId();
+ FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
+ vendor_id, product_id, keyboardSystemEvent, keyCode, modifierState);
+ }
+
+ /**
+ * Function to log the KeyboardConfigured
+ * {@link com.android.os.input.KeyboardConfigured} atom
+ *
+ * @param inputDevice Input device
+ * @param keyboardLayoutConfigurations List of keyboard configurations
+ * @param isFirstTimeConfiguration Whether keyboard is configured for the first time
+ */
+ public static void logKeyboardConfiguredAtom(InputDevice inputDevice,
+ List<KeyboardLayoutConfiguration> keyboardLayoutConfigurations,
+ boolean isFirstTimeConfiguration) {
+ int vendor_id = inputDevice.getVendorId();
+ int product_id = inputDevice.getProductId();
+
+ // Creating proto to log nested field KeyboardLayoutConfig in atom
+ ProtoOutputStream proto = new ProtoOutputStream();
+
+ for (KeyboardLayoutConfiguration keyboardLayoutConfiguration :
+ keyboardLayoutConfigurations) {
+ addKeyboardLayoutConfigurationToProto(proto, keyboardLayoutConfiguration);
+ }
+ // Push the atom to Statsd
+ FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_CONFIGURED,
+ isFirstTimeConfiguration, vendor_id, product_id, proto.getBytes());
+ }
+
+ /**
+ * Populate the KeyboardLayoutConfig proto which is a repeated proto
+ * in the RepeatedKeyboardLayoutConfig proto with values from the
+ * {@link KeyboardLayoutConfiguration} class
+ * The proto definitions can be found at:
+ * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto"
+ *
+ * @param proto Representing the nested proto RepeatedKeyboardLayoutConfig
+ * @param keyboardLayoutConfiguration Class containing the fields for populating the
+ * KeyboardLayoutConfig proto
+ */
+ private static void addKeyboardLayoutConfigurationToProto(ProtoOutputStream proto,
+ KeyboardLayoutConfiguration keyboardLayoutConfiguration) {
+ // Start a new KeyboardLayoutConfig proto.
+ long keyboardLayoutConfigToken = proto.start(
+ RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG);
+ proto.write(KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG,
+ keyboardLayoutConfiguration.getKeyboardLanguageTag());
+ proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE,
+ keyboardLayoutConfiguration.getKeyboardLayoutType());
+ proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME,
+ keyboardLayoutConfiguration.getKeyboardLayoutName());
+ proto.write(KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA,
+ keyboardLayoutConfiguration.getLayoutSelectionCriteria());
+ proto.end(keyboardLayoutConfigToken);
+ }
+
+ /**
+ * Java class representing the proto KeyboardLayoutConfig defined in
+ * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto"
+ *
+ * @see com.android.os.input.KeyboardConfigured
+ */
+ public static class KeyboardLayoutConfiguration {
+ // KeyboardLayoutType in "frameworks/base/core/res/res/values/attrs.xml"
+ // contains mapping for enums to int
+ int mKeyboardLayoutType;
+ String mKeyboardLanguageTag;
+ KeyboardLayout mKeyboardLayout;
+ @LayoutSelectionCriteria int mLayoutSelectionCriteria;
+
+ @Retention(SOURCE)
+ @IntDef(prefix = { "LAYOUT_SELECTION_CRITERIA_" }, value = {
+ LAYOUT_SELECTION_CRITERIA_USER,
+ LAYOUT_SELECTION_CRITERIA_DEVICE,
+ LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+ })
+ public @interface LayoutSelectionCriteria {}
+
+ /** Manual selection by user */
+ public static final int LAYOUT_SELECTION_CRITERIA_USER = 0;
+
+ /** Auto-detection based on device provided language tag and layout type */
+ public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 1;
+
+ /** Auto-detection based on IME provided language tag and layout type */
+ public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 2;
+
+ KeyboardLayoutConfiguration(int keyboardLayoutType,
+ String keyboardLanguageTag,
+ KeyboardLayout keyboardLayout,
+ @LayoutSelectionCriteria int layoutSelectionCriteria) {
+ mKeyboardLayoutType = keyboardLayoutType;
+ mKeyboardLanguageTag = keyboardLanguageTag;
+ mKeyboardLayout = keyboardLayout;
+ mLayoutSelectionCriteria = layoutSelectionCriteria;
+ }
+ int getKeyboardLayoutType() {
+ return mKeyboardLayoutType;
+ }
+
+ String getKeyboardLanguageTag() {
+ return mKeyboardLanguageTag;
+ }
+
+ String getKeyboardLayoutName() {
+ return mKeyboardLayout.getLabel();
+ }
+
+ @LayoutSelectionCriteria int getLayoutSelectionCriteria() {
+ return mLayoutSelectionCriteria;
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3e81f46..2806a11 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -124,6 +124,7 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioSystem;
@@ -205,6 +206,7 @@
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.AccessibilityManagerInternal;
import com.android.server.ExtconStateObserver;
@@ -215,6 +217,7 @@
import com.android.server.UiThread;
import com.android.server.display.BrightnessUtils;
import com.android.server.input.InputManagerInternal;
+import com.android.server.input.KeyboardMetricsCollector;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.KeyCombinationManager.TwoKeysCombinationRule;
@@ -536,10 +539,6 @@
int mShortPressOnSleepBehavior;
int mShortPressOnWindowBehavior;
int mPowerVolUpBehavior;
- int mShortPressOnStemPrimaryBehavior;
- int mDoublePressOnStemPrimaryBehavior;
- int mTriplePressOnStemPrimaryBehavior;
- int mLongPressOnStemPrimaryBehavior;
boolean mStylusButtonsEnabled = true;
boolean mHasSoftInput = false;
boolean mHapticTextHandleEnabled;
@@ -553,6 +552,12 @@
int mSearchKeyBehavior;
ComponentName mSearchKeyTargetActivity;
+ // Key Behavior - Stem Primary
+ private int mShortPressOnStemPrimaryBehavior;
+ private int mDoublePressOnStemPrimaryBehavior;
+ private int mTriplePressOnStemPrimaryBehavior;
+ private int mLongPressOnStemPrimaryBehavior;
+
private boolean mHandleVolumeKeysInWM;
private boolean mPendingKeyguardOccluded;
@@ -676,6 +681,7 @@
private static final int MSG_LAUNCH_ASSIST = 23;
private static final int MSG_RINGER_TOGGLE_CHORD = 24;
private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
+ private static final int MSG_LOG_KEYBOARD_SYSTEM_EVENT = 26;
private class PolicyHandler extends Handler {
@Override
@@ -749,6 +755,9 @@
case MSG_SWITCH_KEYBOARD_LAYOUT:
handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
+ case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
+ handleKeyboardSystemEvent(msg.arg2, (KeyEvent) msg.obj);
+ break;
}
}
}
@@ -1991,6 +2000,21 @@
Supplier<GlobalActions> getGlobalActionsFactory() {
return () -> new GlobalActions(mContext, mWindowManagerFuncs);
}
+
+ KeyguardServiceDelegate getKeyguardServiceDelegate() {
+ return new KeyguardServiceDelegate(mContext,
+ new StateCallback() {
+ @Override
+ public void onTrustedChanged() {
+ mWindowManagerFuncs.notifyKeyguardTrustedChanged();
+ }
+
+ @Override
+ public void onShowingChanged() {
+ mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
+ }
+ });
+ }
}
/** {@inheritDoc} */
@@ -2248,18 +2272,7 @@
mKeyguardDrawnTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyguardDrawnTimeout);
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
- new StateCallback() {
- @Override
- public void onTrustedChanged() {
- mWindowManagerFuncs.notifyKeyguardTrustedChanged();
- }
-
- @Override
- public void onShowingChanged() {
- mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
- }
- });
+ mKeyguardDelegate = injector.getKeyguardServiceDelegate();
initKeyCombinationRules();
initSingleKeyGestureRules();
mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
@@ -2284,6 +2297,7 @@
cancelPendingScreenshotChordAction();
}
});
+
if (mHasFeatureWatch) {
mKeyCombinationManager.addRule(
new TwoKeysCombinationRule(KEYCODE_POWER, KEYCODE_STEM_PRIMARY) {
@@ -2903,7 +2917,30 @@
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
};
+ /**
+ * Log the keyboard shortcuts without blocking the current thread.
+ *
+ * We won't log keyboard events when the input device is null
+ * or when it is virtual.
+ */
+ private void handleKeyboardSystemEvent(int keyboardSystemEvent, KeyEvent event) {
+ final InputManager inputManager = mContext.getSystemService(InputManager.class);
+ final InputDevice inputDevice = inputManager != null
+ ? inputManager.getInputDevice(event.getDeviceId()) : null;
+ if (inputDevice != null && !inputDevice.isVirtual()) {
+ KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(
+ inputDevice, keyboardSystemEvent,
+ new int[]{event.getKeyCode()}, event.getMetaState());
+ }
+ }
+
+ private void logKeyboardSystemsEvent(KeyEvent event, int keyboardSystemEvent) {
+ mHandler.obtainMessage(MSG_LOG_KEYBOARD_SYSTEM_EVENT, 0, keyboardSystemEvent, event)
+ .sendToTarget();
+ }
+
// TODO(b/117479243): handle it in InputPolicy
+ // TODO (b/283241997): Add the remaining keyboard shortcut logging after refactoring
/** {@inheritDoc} */
@Override
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
@@ -2957,6 +2994,8 @@
switch(keyCode) {
case KeyEvent.KEYCODE_HOME:
+ logKeyboardSystemsEvent(event, FrameworkStatsLog
+ .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME);
return handleHomeShortcuts(displayId, focusedToken, event);
case KeyEvent.KEYCODE_MENU:
// Hijack modified menu keys for debugging features
@@ -2974,6 +3013,8 @@
case KeyEvent.KEYCODE_RECENT_APPS:
if (down && repeatCount == 0) {
showRecentApps(false /* triggeredFromAltTab */);
+ logKeyboardSystemsEvent(event, FrameworkStatsLog
+ .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS);
}
return key_consumed;
case KeyEvent.KEYCODE_APP_SWITCH:
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0ebec11..53a4752 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2926,15 +2926,6 @@
}
}
- // If the matching task is already in the adjacent task of the launch target. Adjust to use
- // the adjacent task as its launch target. So the existing task will be launched into the
- // closer one and won't be reparent redundantly.
- final Task adjacentTargetTask = mTargetRootTask.getAdjacentTask();
- if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)
- && intentTask.isOnTop()) {
- mTargetRootTask = adjacentTargetTask;
- }
-
// If the target task is not in the front, then we need to bring it to the front...
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
// the same behavior as if a new instance was being started, which means not bringing it
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 65771d1..9468861 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -176,7 +176,7 @@
// TODO(b/266197298): Remove this by a more general protocol from the insets providers.
private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH =
- SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", false);
+ SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true);
private final WindowManagerService mService;
private final Context mContext;
@@ -271,13 +271,13 @@
private WindowState mSystemUiControllingWindow;
// Candidate window to determine the color of navigation bar. The window needs to be top
- // fullscreen-app windows or dim layers that are intersecting with the window frame of status
- // bar.
+ // fullscreen-app windows or dim layers that are intersecting with the window frame of
+ // navigation bar.
private WindowState mNavBarColorWindowCandidate;
- // The window to determine opacity and background of translucent navigation bar. The window
- // needs to be opaque.
- private WindowState mNavBarBackgroundWindow;
+ // Candidate window to determine opacity and background of translucent navigation bar.
+ // The window frame must intersect the frame of navigation bar.
+ private WindowState mNavBarBackgroundWindowCandidate;
/**
* A collection of {@link AppearanceRegion} to indicate that which region of status bar applies
@@ -961,12 +961,6 @@
if (!win.mSession.mCanSetUnrestrictedGestureExclusion) {
attrs.privateFlags &= ~PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
}
-
- final InsetsSourceProvider provider = win.getControllableInsetProvider();
- if (provider != null && provider.getSource().insetsRoundedCornerFrame()
- != attrs.insetsRoundedCornerFrame) {
- provider.getSource().setInsetsRoundedCornerFrame(attrs.insetsRoundedCornerFrame);
- }
}
/**
@@ -1104,9 +1098,11 @@
} else {
overrideProviders = null;
}
- mDisplayContent.getInsetsStateController().getOrCreateSourceProvider(
- provider.getId(), provider.getType()).setWindowContainer(
- win, frameProvider, overrideProviders);
+ final InsetsSourceProvider sourceProvider = mDisplayContent
+ .getInsetsStateController().getOrCreateSourceProvider(provider.getId(),
+ provider.getType());
+ sourceProvider.getSource().setFlags(provider.getFlags());
+ sourceProvider.setWindowContainer(win, frameProvider, overrideProviders);
mInsetsSourceWindowsExceptIme.add(win);
}
}
@@ -1387,7 +1383,7 @@
mBottomGestureHost = null;
mTopFullscreenOpaqueWindowState = null;
mNavBarColorWindowCandidate = null;
- mNavBarBackgroundWindow = null;
+ mNavBarBackgroundWindowCandidate = null;
mStatusBarAppearanceRegionList.clear();
mLetterboxDetails.clear();
mStatusBarBackgroundWindows.clear();
@@ -1514,8 +1510,8 @@
mNavBarColorWindowCandidate = win;
addSystemBarColorApp(win);
}
- if (mNavBarBackgroundWindow == null) {
- mNavBarBackgroundWindow = win;
+ if (mNavBarBackgroundWindowCandidate == null) {
+ mNavBarBackgroundWindowCandidate = win;
}
}
@@ -1539,12 +1535,19 @@
}
if (isOverlappingWithNavBar(win) && mNavBarColorWindowCandidate == null) {
mNavBarColorWindowCandidate = win;
+ addSystemBarColorApp(win);
}
- } else if (appWindow && attached == null && mNavBarColorWindowCandidate == null
+ } else if (appWindow && attached == null
+ && (mNavBarColorWindowCandidate == null || mNavBarBackgroundWindowCandidate == null)
&& win.getFrame().contains(
getBarContentFrameForWindow(win, Type.navigationBars()))) {
- mNavBarColorWindowCandidate = win;
- addSystemBarColorApp(win);
+ if (mNavBarColorWindowCandidate == null) {
+ mNavBarColorWindowCandidate = win;
+ addSystemBarColorApp(win);
+ }
+ if (mNavBarBackgroundWindowCandidate == null) {
+ mNavBarBackgroundWindowCandidate = win;
+ }
}
}
@@ -2483,7 +2486,7 @@
return win.isFullyTransparentBarAllowed(getBarContentFrameForWindow(win, type));
}
- private boolean drawsBarBackground(WindowState win) {
+ private static boolean drawsBarBackground(WindowState win) {
if (win == null) {
return true;
}
@@ -2523,7 +2526,11 @@
*/
private int configureNavBarOpacity(int appearance, boolean multiWindowTaskVisible,
boolean freeformRootTaskVisible) {
- final boolean drawBackground = drawsBarBackground(mNavBarBackgroundWindow);
+ final WindowState navBackgroundWin = chooseNavigationBackgroundWindow(
+ mNavBarBackgroundWindowCandidate,
+ mDisplayContent.mInputMethodWindow,
+ mNavigationBarPosition);
+ final boolean drawBackground = navBackgroundWin != null;
if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
if (drawBackground) {
@@ -2543,7 +2550,7 @@
}
}
- if (!isFullyTransparentAllowed(mNavBarBackgroundWindow, Type.navigationBars())) {
+ if (!isFullyTransparentAllowed(navBackgroundWin, Type.navigationBars())) {
appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
}
@@ -2554,6 +2561,20 @@
return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS;
}
+ @VisibleForTesting
+ @Nullable
+ static WindowState chooseNavigationBackgroundWindow(WindowState candidate,
+ WindowState imeWindow, @NavigationBarPosition int navBarPosition) {
+ if (imeWindow != null && imeWindow.isVisible() && navBarPosition == NAV_BAR_BOTTOM
+ && drawsBarBackground(imeWindow)) {
+ return imeWindow;
+ }
+ if (drawsBarBackground(candidate)) {
+ return candidate;
+ }
+ return null;
+ }
+
private boolean isImmersiveMode(WindowState win) {
if (win == null) {
return false;
@@ -2726,9 +2747,9 @@
pw.print(prefix); pw.print("mNavBarColorWindowCandidate=");
pw.println(mNavBarColorWindowCandidate);
}
- if (mNavBarBackgroundWindow != null) {
- pw.print(prefix); pw.print("mNavBarBackgroundWindow=");
- pw.println(mNavBarBackgroundWindow);
+ if (mNavBarBackgroundWindowCandidate != null) {
+ pw.print(prefix); pw.print("mNavBarBackgroundWindowCandidate=");
+ pw.println(mNavBarBackgroundWindowCandidate);
}
if (mLastStatusBarAppearanceRegions != null) {
pw.print(prefix); pw.println("mLastStatusBarAppearanceRegions=");
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 2583514..4a3d0c1 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -181,7 +181,11 @@
}
} finally {
if (surface != null) {
- surface.release();
+ try (final SurfaceControl.Transaction transaction =
+ mService.mTransactionFactory.get()) {
+ transaction.remove(surface);
+ transaction.apply();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ddf96c5..698c9ab 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -440,8 +440,8 @@
return originalState;
}
- void onInsetsModified(InsetsControlTarget caller) {
- mStateController.onInsetsModified(caller);
+ void onRequestedVisibleTypesChanged(InsetsControlTarget caller) {
+ mStateController.onRequestedVisibleTypesChanged(caller);
checkAbortTransient(caller);
updateBarControlTarget(mFocusedWin);
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index b7eaf25..7f845e6 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -175,7 +175,7 @@
if (windowContainer == null) {
setServerVisible(false);
mSource.setVisibleFrame(null);
- mSource.setInsetsRoundedCornerFrame(false);
+ mSource.setFlags(0, 0xffffffff);
mSourceFrame.setEmpty();
} else {
mWindowContainer.getInsetsSourceProviders().put(mSource.getId(), this);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 249ead0..addb521 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -190,7 +190,7 @@
}
}
- void onInsetsModified(InsetsControlTarget caller) {
+ void onRequestedVisibleTypesChanged(InsetsControlTarget caller) {
boolean changed = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
changed |= mProviders.valueAt(i).updateClientVisibility(caller);
@@ -352,7 +352,7 @@
// to the clients, so that the clients can change the current visibilities to the
// requested visibilities with animations.
for (int i = newControlTargets.size() - 1; i >= 0; i--) {
- onInsetsModified(newControlTargets.valueAt(i));
+ onRequestedVisibleTypesChanged(newControlTargets.valueAt(i));
}
newControlTargets.clear();
});
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index d83c861..c243988 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1428,7 +1428,8 @@
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
if (source.getType() == WindowInsets.Type.navigationBars()
- && source.insetsRoundedCornerFrame() && source.isVisible()) {
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)
+ && source.isVisible()) {
return source;
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e47787e..9ef5ed0 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1104,6 +1104,10 @@
// front unless overridden by the provided activity options
mTasks.remove(taskIndex);
mTasks.add(0, task);
+ if (taskIndex != 0) {
+ // Only notify when position changes
+ mTaskNotificationController.notifyTaskListUpdated();
+ }
if (DEBUG_RECENTS) {
Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
@@ -1552,7 +1556,7 @@
task.affinity != null && task.affinity.equals(t.affinity);
final boolean sameIntent = intent != null && intent.filterEquals(trIntent);
boolean multiTasksAllowed = false;
- final int flags = intent.getFlags();
+ final int flags = intent != null ? intent.getFlags() : 0;
if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0
&& (flags & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
multiTasksAllowed = true;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 7b10c63..b49c5fb 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -687,11 +687,11 @@
@Override
public void updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes) {
synchronized (mService.mGlobalLock) {
- final WindowState windowState = mService.windowForClientLocked(this, window,
+ final WindowState win = mService.windowForClientLocked(this, window,
false /* throwOnError */);
- if (windowState != null) {
- windowState.setRequestedVisibleTypes(requestedVisibleTypes);
- windowState.getDisplayContent().getInsetsPolicy().onInsetsModified(windowState);
+ if (win != null) {
+ win.setRequestedVisibleTypes(requestedVisibleTypes);
+ win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bb6f805..ce4f445 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -49,6 +49,7 @@
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -1271,6 +1272,10 @@
if (isPersistable) {
mLastTimeMoved = System.currentTimeMillis();
}
+ if (toTop && inRecents) {
+ // If task is in recents, ensure it is at the top
+ mTaskSupervisor.mRecentTasks.add(this);
+ }
}
// Close up recents linked list.
@@ -2858,7 +2863,7 @@
getDisplayContent().getInsetsStateController().getRawInsetsState();
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
- if (source.insetsRoundedCornerFrame()) {
+ if (source.hasFlags(FLAG_INSETS_ROUNDED_CORNER)) {
animationBounds.inset(source.calculateVisibleInsets(animationBounds));
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0152666..4bc4c26 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -4141,7 +4141,7 @@
getDisplayContent().getInsetsStateController().getSourceProviders();
for (int i = providers.size(); i >= 0; i--) {
final InsetsSourceProvider insetProvider = providers.valueAt(i);
- if (!insetProvider.getSource().insetsRoundedCornerFrame()) {
+ if (!insetProvider.getSource().hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e33c6f0..9c636ea 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4537,7 +4537,8 @@
return;
}
dc.mRemoteInsetsControlTarget.setRequestedVisibleTypes(requestedVisibleTypes);
- dc.getInsetsStateController().onInsetsModified(dc.mRemoteInsetsControlTarget);
+ dc.getInsetsStateController().onRequestedVisibleTypesChanged(
+ dc.mRemoteInsetsControlTarget);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index f0d718a..8587270 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1596,8 +1596,8 @@
}
PointerIconStyle NativeInputManager::getDefaultStylusIconId() {
- // TODO: add resource for default stylus icon and change this
- return PointerIconStyle::TYPE_CROSSHAIR;
+ // Use the empty icon as the default pointer icon for a hovering stylus.
+ return PointerIconStyle::TYPE_NULL;
}
PointerIconStyle NativeInputManager::getCustomPointerIconId() {
@@ -2214,13 +2214,25 @@
jCapability |= env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightCapabilityColorRgb);
}
+
+ ScopedLocalRef<jintArray> jPreferredBrightnessLevels{env};
+ if (!lightInfo.preferredBrightnessLevels.empty()) {
+ std::vector<int32_t> vec;
+ for (auto it : lightInfo.preferredBrightnessLevels) {
+ vec.push_back(ftl::to_underlying(it));
+ }
+ jPreferredBrightnessLevels.reset(env->NewIntArray(vec.size()));
+ env->SetIntArrayRegion(jPreferredBrightnessLevels.get(), 0, vec.size(), vec.data());
+ }
+
ScopedLocalRef<jobject> lightObj(env,
env->NewObject(gLightClassInfo.clazz,
gLightClassInfo.constructor,
static_cast<jint>(lightInfo.id),
env->NewStringUTF(lightInfo.name.c_str()),
static_cast<jint>(lightInfo.ordinal),
- jTypeId, jCapability));
+ jTypeId, jCapability,
+ jPreferredBrightnessLevels.get()));
// Add light object to list
env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
}
@@ -2846,7 +2858,7 @@
FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light");
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>",
- "(ILjava/lang/String;III)V");
+ "(ILjava/lang/String;III[I)V");
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
gLightClassInfo.lightTypeInput =
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index af84180..991248a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -3255,6 +3255,12 @@
Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
return;
}
+ if (!deviceHasConfigString(context, R.string.config_defaultContentProtectionService)) {
+ Slog.d(
+ TAG,
+ "ContentProtectionService disabled because resource is not overlaid,"
+ + " ContentCaptureService still enabled");
+ }
}
t.traceBegin("StartContentCaptureService");
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 8dc0ac6..efd82fa 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -813,7 +813,7 @@
any(HysteresisLevels.class),
any(HysteresisLevels.class),
eq(mContext),
- any(HighBrightnessModeController.class),
+ any(BrightnessRangeController.class),
any(BrightnessThrottler.class),
isNull(),
anyInt(),
@@ -1062,7 +1062,7 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController,
+ BrightnessRangeController brightnessRangeController,
BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper,
int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux,
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 5c0810f..a93640b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -819,7 +819,7 @@
any(HysteresisLevels.class),
any(HysteresisLevels.class),
eq(mContext),
- any(HighBrightnessModeController.class),
+ any(BrightnessRangeController.class),
any(BrightnessThrottler.class),
isNull(),
anyInt(),
@@ -1038,7 +1038,7 @@
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- HighBrightnessModeController hbmController,
+ BrightnessRangeController brightnessRangeController,
BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper,
int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux,
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index cfeaf0b..2b9a227 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -28,6 +28,7 @@
"services.accessibility",
"services.appwidget",
"services.autofill",
+ "services.contentcapture",
"services.backup",
"services.companion",
"services.core",
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index d5d06d3..046b01c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -16,8 +16,10 @@
package com.android.server.biometrics.sensors.face.aidl;
+import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -205,7 +207,9 @@
client.onAuthenticated(new Face("friendly", 1 /* faceId */, 2 /* deviceId */),
true /* authenticated */, new ArrayList<>());
- verify(mCancellationSignal).cancel();
+ verify(mCancellationSignal, never()).cancel();
+ verify(mClientMonitorCallbackConverter)
+ .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt());
}
private FaceAuthenticationClient createClient() throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index f8f40fe..c383a96 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -399,7 +401,9 @@
mLooper.moveTimeForward(10);
mLooper.dispatchAll();
- verify(mCancellationSignal).cancel();
+ verify(mCancellationSignal, never()).cancel();
+ verify(mClientMonitorCallbackConverter)
+ .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt());
}
private FingerprintAuthenticationClient createClient() throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
new file mode 100644
index 0000000..c872a11
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 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.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.ContentCaptureOptions;
+import android.content.Context;
+import android.content.pm.UserInfo;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Test for {@link ContentCaptureManagerService}.
+ *
+ * <p>Run with: {@code atest
+ * FrameworksServicesTests:com.android.server.contentcapture.ContentCaptureManagerServiceTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@SuppressWarnings("GuardedBy") // Service not really running, no need to expose locks
+public class ContentCaptureManagerServiceTest {
+
+ private static final int USER_ID = 1234;
+
+ private static final String PACKAGE_NAME = "com.test.package";
+
+ private static final Context sContext = ApplicationProvider.getApplicationContext();
+
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock private UserManagerInternal mMockUserManagerInternal;
+
+ private ContentCaptureManagerService mContentCaptureManagerService;
+
+ @Before
+ public void setup() {
+ when(mMockUserManagerInternal.getUserInfos()).thenReturn(new UserInfo[0]);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
+ mContentCaptureManagerService = new ContentCaptureManagerService(sContext);
+ }
+
+ @Test
+ public void getOptions_notAllowlisted() {
+ ContentCaptureOptions actual =
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions(
+ USER_ID, PACKAGE_NAME);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void getOptions_allowlisted_contentCaptureReceiver() {
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
+
+ ContentCaptureOptions actual =
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions(
+ USER_ID, PACKAGE_NAME);
+
+ assertThat(actual).isNotNull();
+ assertThat(actual.enableReceiver).isTrue();
+ assertThat(actual.contentProtectionOptions.enableReceiver).isFalse();
+ assertThat(actual.whitelistedComponents).isNull();
+ }
+
+ @Test
+ public void getOptions_allowlisted_bothReceivers() {
+ mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
+
+ ContentCaptureOptions actual =
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions(
+ USER_ID, PACKAGE_NAME);
+
+ assertThat(actual).isNotNull();
+ assertThat(actual.enableReceiver).isTrue();
+ assertThat(actual.contentProtectionOptions.enableReceiver).isTrue();
+ assertThat(actual.whitelistedComponents).isNull();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java
new file mode 100644
index 0000000..ba9956a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.contentprotection;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test for {@link ContentProtectionBlocklistManager}.
+ *
+ * <p>Run with: {@code atest
+ * FrameworksServicesTests:
+ * com.android.server.contentprotection.ContentProtectionBlocklistManagerTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ContentProtectionBlocklistManagerTest {
+
+ private static final String FIRST_PACKAGE_NAME = "com.test.first.package.name";
+
+ private static final String SECOND_PACKAGE_NAME = "com.test.second.package.name";
+
+ private static final String UNLISTED_PACKAGE_NAME = "com.test.unlisted.package.name";
+
+ private static final String PACKAGE_NAME_BLOCKLIST_FILENAME =
+ "/product/etc/res/raw/content_protection/package_name_blocklist.txt";
+
+ private static final PackageInfo PACKAGE_INFO = new PackageInfo();
+
+ private static final List<String> LINES =
+ ImmutableList.of(FIRST_PACKAGE_NAME, SECOND_PACKAGE_NAME);
+
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock private ContentProtectionPackageManager mMockContentProtectionPackageManager;
+
+ private final List<String> mReadRawFiles = new ArrayList<>();
+
+ private ContentProtectionBlocklistManager mContentProtectionBlocklistManager;
+
+ @Before
+ public void setup() {
+ mContentProtectionBlocklistManager = new TestContentProtectionBlocklistManager();
+ }
+
+ @Test
+ public void isAllowed_blocklistNotLoaded() {
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ assertThat(mReadRawFiles).isEmpty();
+ verifyZeroInteractions(mMockContentProtectionPackageManager);
+ }
+
+ @Test
+ public void isAllowed_inBlocklist() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ verifyZeroInteractions(mMockContentProtectionPackageManager);
+ }
+
+ @Test
+ public void isAllowed_packageInfoNotFound() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+ when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
+ .thenReturn(null);
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ verify(mMockContentProtectionPackageManager, never())
+ .hasRequestedInternetPermissions(any());
+ verify(mMockContentProtectionPackageManager, never()).isSystemApp(any());
+ verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
+ }
+
+ @Test
+ public void isAllowed_notRequestedInternet() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+ when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
+ .thenReturn(PACKAGE_INFO);
+ when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
+ .thenReturn(false);
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ verify(mMockContentProtectionPackageManager, never()).isSystemApp(any());
+ verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
+ }
+
+ @Test
+ public void isAllowed_systemApp() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+ when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
+ .thenReturn(PACKAGE_INFO);
+ when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
+ .thenReturn(true);
+ when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(true);
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
+ }
+
+ @Test
+ public void isAllowed_updatedSystemApp() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+ when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
+ .thenReturn(PACKAGE_INFO);
+ when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
+ .thenReturn(true);
+ when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(true);
+ when(mMockContentProtectionPackageManager.isUpdatedSystemApp(PACKAGE_INFO))
+ .thenReturn(true);
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void isAllowed_allowed() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
+ when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
+ .thenReturn(PACKAGE_INFO);
+ when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
+ .thenReturn(true);
+ when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(false);
+ when(mMockContentProtectionPackageManager.isUpdatedSystemApp(PACKAGE_INFO))
+ .thenReturn(false);
+
+ boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
+
+ assertThat(actual).isTrue();
+ }
+
+ @Test
+ public void updateBlocklist_negativeSize() {
+ mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ -1);
+ assertThat(mReadRawFiles).isEmpty();
+
+ mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+ verify(mMockContentProtectionPackageManager).getPackageInfo(FIRST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void updateBlocklist_zeroSize() {
+ mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ 0);
+ assertThat(mReadRawFiles).isEmpty();
+
+ mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+ verify(mMockContentProtectionPackageManager).getPackageInfo(FIRST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void updateBlocklist_positiveSize_belowTotal() {
+ mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ 1);
+ assertThat(mReadRawFiles).containsExactly(PACKAGE_NAME_BLOCKLIST_FILENAME);
+
+ mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+ mContentProtectionBlocklistManager.isAllowed(SECOND_PACKAGE_NAME);
+
+ verify(mMockContentProtectionPackageManager, never()).getPackageInfo(FIRST_PACKAGE_NAME);
+ verify(mMockContentProtectionPackageManager).getPackageInfo(SECOND_PACKAGE_NAME);
+ }
+
+ @Test
+ public void updateBlocklist_positiveSize_aboveTotal() {
+ mContentProtectionBlocklistManager.updateBlocklist(LINES.size() + 1);
+ assertThat(mReadRawFiles).containsExactly(PACKAGE_NAME_BLOCKLIST_FILENAME);
+
+ mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
+ mContentProtectionBlocklistManager.isAllowed(SECOND_PACKAGE_NAME);
+
+ verify(mMockContentProtectionPackageManager, never()).getPackageInfo(FIRST_PACKAGE_NAME);
+ verify(mMockContentProtectionPackageManager, never()).getPackageInfo(SECOND_PACKAGE_NAME);
+ }
+
+ private final class TestContentProtectionBlocklistManager
+ extends ContentProtectionBlocklistManager {
+
+ TestContentProtectionBlocklistManager() {
+ super(mMockContentProtectionPackageManager);
+ }
+
+ @Override
+ protected List<String> readLinesFromRawFile(@NonNull String filename) {
+ mReadRawFiles.add(filename);
+ return LINES;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java
new file mode 100644
index 0000000..7d45ea4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.contentprotection;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.Manifest.permission;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager.PackageInfoFlags;
+import android.testing.TestableContext;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Test for {@link ContentProtectionPackageManager}.
+ *
+ * <p>Run with: {@code atest
+ * FrameworksServicesTests:com.android.server.contentprotection.ContentProtectionPackageManagerTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ContentProtectionPackageManagerTest {
+ private static final String PACKAGE_NAME = "PACKAGE_NAME";
+
+ private static final PackageInfo EMPTY_PACKAGE_INFO = new PackageInfo();
+
+ private static final PackageInfo SYSTEM_APP_PACKAGE_INFO = createSystemAppPackageInfo();
+
+ private static final PackageInfo UPDATED_SYSTEM_APP_PACKAGE_INFO =
+ createUpdatedSystemAppPackageInfo();
+
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(ApplicationProvider.getApplicationContext());
+
+ @Mock private PackageManager mMockPackageManager;
+
+ private ContentProtectionPackageManager mContentProtectionPackageManager;
+
+ @Before
+ public void setup() {
+ mContext.setMockPackageManager(mMockPackageManager);
+ mContentProtectionPackageManager = new ContentProtectionPackageManager(mContext);
+ }
+
+ @Test
+ public void getPackageInfo_found() throws Exception {
+ PackageInfo expected = createPackageInfo(/* flags= */ 0);
+ when(mMockPackageManager.getPackageInfo(eq(PACKAGE_NAME), any(PackageInfoFlags.class)))
+ .thenReturn(expected);
+
+ PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getPackageInfo_notFound() throws Exception {
+ when(mMockPackageManager.getPackageInfo(eq(PACKAGE_NAME), any(PackageInfoFlags.class)))
+ .thenThrow(new NameNotFoundException());
+
+ PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void getPackageInfo_null() {
+ PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void isSystemApp_true() {
+ boolean actual = mContentProtectionPackageManager.isSystemApp(SYSTEM_APP_PACKAGE_INFO);
+
+ assertThat(actual).isTrue();
+ }
+
+ @Test
+ public void isSystemApp_false() {
+ boolean actual =
+ mContentProtectionPackageManager.isSystemApp(UPDATED_SYSTEM_APP_PACKAGE_INFO);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void isSystemApp_noApplicationInfo() {
+ boolean actual = mContentProtectionPackageManager.isSystemApp(EMPTY_PACKAGE_INFO);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void isUpdatedSystemApp_true() {
+ boolean actual =
+ mContentProtectionPackageManager.isUpdatedSystemApp(
+ UPDATED_SYSTEM_APP_PACKAGE_INFO);
+
+ assertThat(actual).isTrue();
+ }
+
+ @Test
+ public void isUpdatedSystemApp_false() {
+ boolean actual =
+ mContentProtectionPackageManager.isUpdatedSystemApp(SYSTEM_APP_PACKAGE_INFO);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void isUpdatedSystemApp_noApplicationInfo() {
+ boolean actual = mContentProtectionPackageManager.isUpdatedSystemApp(EMPTY_PACKAGE_INFO);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void hasRequestedInternetPermissions_true() {
+ PackageInfo packageInfo = createPackageInfo(new String[] {permission.INTERNET});
+
+ boolean actual =
+ mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo);
+
+ assertThat(actual).isTrue();
+ }
+
+ @Test
+ public void hasRequestedInternetPermissions_false() {
+ PackageInfo packageInfo = createPackageInfo(new String[] {permission.ACCESS_FINE_LOCATION});
+
+ boolean actual =
+ mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo);
+
+ assertThat(actual).isFalse();
+ }
+
+ @Test
+ public void hasRequestedInternetPermissions_noRequestedPermissions() {
+ boolean actual =
+ mContentProtectionPackageManager.hasRequestedInternetPermissions(
+ EMPTY_PACKAGE_INFO);
+
+ assertThat(actual).isFalse();
+ }
+
+ private static PackageInfo createSystemAppPackageInfo() {
+ return createPackageInfo(ApplicationInfo.FLAG_SYSTEM);
+ }
+
+ private static PackageInfo createUpdatedSystemAppPackageInfo() {
+ return createPackageInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ }
+
+ private static PackageInfo createPackageInfo(int flags) {
+ return createPackageInfo(flags, /* requestedPermissions= */ new String[0]);
+ }
+
+ private static PackageInfo createPackageInfo(String[] requestedPermissions) {
+ return createPackageInfo(/* flags= */ 0, requestedPermissions);
+ }
+
+ private static PackageInfo createPackageInfo(int flags, String[] requestedPermissions) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = PACKAGE_NAME;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = PACKAGE_NAME;
+ packageInfo.applicationInfo.flags = flags;
+ packageInfo.requestedPermissions = requestedPermissions;
+ return packageInfo;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 962e867..a6acd60 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -85,7 +85,7 @@
@Mock HysteresisLevels mAmbientBrightnessThresholdsIdle;
@Mock HysteresisLevels mScreenBrightnessThresholdsIdle;
@Mock Handler mNoOpHandler;
- @Mock HighBrightnessModeController mHbmController;
+ @Mock BrightnessRangeController mBrightnessRangeController;
@Mock BrightnessThrottler mBrightnessThrottler;
@Before
@@ -134,12 +134,15 @@
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle,
- mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy,
- AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG, userLux, userBrightness
+ mContext, mBrightnessRangeController, mBrightnessThrottler,
+ mIdleBrightnessMappingStrategy, AMBIENT_LIGHT_HORIZON_SHORT,
+ AMBIENT_LIGHT_HORIZON_LONG, userLux, userBrightness
);
- when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT);
- when(mHbmController.getCurrentBrightnessMin()).thenReturn(BRIGHTNESS_MIN_FLOAT);
+ when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn(
+ BRIGHTNESS_MAX_FLOAT);
+ when(mBrightnessRangeController.getCurrentBrightnessMin()).thenReturn(
+ BRIGHTNESS_MIN_FLOAT);
// Disable brightness throttling by default. Individual tests can enable it as needed.
when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
when(mBrightnessThrottler.isThrottled()).thenReturn(false);
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 817b245..642f54c 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -60,6 +60,114 @@
}
@Test
+ public void testLoadBrightness() {
+ final String uniqueDisplayId = "test:123";
+ final DisplayDevice testDisplayDevice = new DisplayDevice(
+ null, null, uniqueDisplayId, null) {
+ @Override
+ public boolean hasStableUniqueId() {
+ return true;
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ return null;
+ }
+ };
+
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <display-states>\n"
+ + " <display unique-id=\"test:123\">\n"
+ + " <brightness-value user-serial=\"1\">0.1</brightness-value>\n"
+ + " <brightness-value user-serial=\"2\">0.2</brightness-value>\n"
+ + " </display>\n"
+ + " </display-states>\n"
+ + "</display-manager-state>\n";
+
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+
+ float brightness = mDataStore.getBrightness(testDisplayDevice, 1);
+ assertEquals(0.1, brightness, 0.01);
+
+ brightness = mDataStore.getBrightness(testDisplayDevice, 2);
+ assertEquals(0.2, brightness, 0.01);
+ }
+
+ @Test
+ public void testSetBrightness_brightnessTagWithNoUserId_updatesToBrightnessTagWithUserId() {
+ final String uniqueDisplayId = "test:123";
+ final DisplayDevice testDisplayDevice =
+ new DisplayDevice(null, null, uniqueDisplayId, null) {
+ @Override
+ public boolean hasStableUniqueId() {
+ return true;
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ return null;
+ }
+ };
+
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <display-states>\n"
+ + " <color-mode>0</color-mode>\n"
+ + " <display unique-id=\"test:123\">\n"
+ + " <brightness-value>0.5</brightness-value>\n"
+ + " </display>\n"
+ + " </display-states>\n"
+ + "</display-manager-state>\n";
+
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+
+ float user1Brightness = mDataStore.getBrightness(testDisplayDevice, 1 /* userSerial */);
+ float user2Brightness = mDataStore.getBrightness(testDisplayDevice, 2 /* userSerial */);
+ assertEquals(0.5, user1Brightness, 0.01);
+ assertEquals(0.5, user2Brightness, 0.01);
+
+ // Override the value for user 2. Default user must have been removed.
+ mDataStore.setBrightness(testDisplayDevice, 0.2f, 2 /* userSerial */ /* brightness*/);
+
+ user1Brightness = mDataStore.getBrightness(testDisplayDevice, 1 /* userSerial */);
+ user2Brightness = mDataStore.getBrightness(testDisplayDevice, 2 /* userSerial */);
+ assertTrue(Float.isNaN(user1Brightness));
+ assertEquals(0.2f, user2Brightness, 0.01);
+
+ // Override the value for user 1. User-specific brightness values should co-exist.
+ mDataStore.setBrightness(testDisplayDevice, 0.1f, 1 /* userSerial */ /* brightness*/);
+ user1Brightness = mDataStore.getBrightness(testDisplayDevice, 1 /* userSerial */);
+ user2Brightness = mDataStore.getBrightness(testDisplayDevice, 2 /* userSerial */);
+ assertEquals(0.1f, user1Brightness, 0.01);
+ assertEquals(0.2f, user2Brightness, 0.01);
+
+ // Validate saveIfNeeded writes user-specific brightnes.
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ mInjector.setWriteStream(baos);
+ mDataStore.saveIfNeeded();
+ mTestLooper.dispatchAll();
+ assertTrue(mInjector.wasWriteSuccessful());
+ TestInjector newInjector = new TestInjector();
+ PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ newInjector.setReadStream(bais);
+ newDataStore.loadIfNeeded();
+
+ user1Brightness = newDataStore.getBrightness(testDisplayDevice, 1 /* userSerial */);
+ user2Brightness = newDataStore.getBrightness(testDisplayDevice, 2 /* userSerial */);
+ float unknownUserBrightness =
+ newDataStore.getBrightness(testDisplayDevice, 999 /* userSerial */);
+ assertEquals(0.1f, user1Brightness, 0.01);
+ assertEquals(0.2f, user2Brightness, 0.01);
+ assertTrue(Float.isNaN(unknownUserBrightness));
+ }
+
+ @Test
public void testLoadingBrightnessConfigurations() {
String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<display-manager-state>\n"
@@ -374,7 +482,7 @@
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
newInjector.setReadStream(bais);
newDataStore.loadIfNeeded();
- assertTrue(Float.isNaN(mDataStore.getBrightness(testDisplayDevice)));
+ assertTrue(Float.isNaN(mDataStore.getBrightness(testDisplayDevice, 1 /* userSerial */)));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index e6d3bbc..c4f4838 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -247,6 +248,7 @@
0.0f);
verify(mBrightnessChangeExecutor).execute(mOnBrightnessChangeRunnable);
verify(mBrightnessSetting).setBrightness(brightnessValue);
+ verify(mBrightnessSetting).setUserSerial(anyInt());
// Does nothing if the value is invalid
mDisplayBrightnessController.updateScreenBrightnessSetting(Float.NaN);
@@ -358,4 +360,28 @@
verify(mBrightnessSetting, never()).getBrightnessNitsForDefaultDisplay();
verify(mBrightnessSetting, never()).setBrightness(brightness);
}
+
+ @Test
+ public void testChangeBrightnessNitsWhenUserChanges() {
+ float brightnessValue1 = 0.3f;
+ float nits1 = 200f;
+ float brightnessValue2 = 0.5f;
+ float nits2 = 300f;
+ AutomaticBrightnessController automaticBrightnessController =
+ mock(AutomaticBrightnessController.class);
+ when(automaticBrightnessController.convertToNits(brightnessValue1)).thenReturn(nits1);
+ when(automaticBrightnessController.convertToNits(brightnessValue2)).thenReturn(nits2);
+ mDisplayBrightnessController.setAutomaticBrightnessController(
+ automaticBrightnessController);
+
+ mDisplayBrightnessController.setBrightness(brightnessValue1, 1 /* user-serial */);
+ verify(mBrightnessSetting).setUserSerial(1);
+ verify(mBrightnessSetting).setBrightness(brightnessValue1);
+ verify(mBrightnessSetting).setBrightnessNitsForDefaultDisplay(nits1);
+
+ mDisplayBrightnessController.setBrightness(brightnessValue2, 2 /* user-serial */);
+ verify(mBrightnessSetting).setUserSerial(2);
+ verify(mBrightnessSetting).setBrightness(brightnessValue2);
+ verify(mBrightnessSetting).setBrightnessNitsForDefaultDisplay(nits2);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 64c05dc..ef15ccb 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -16,6 +16,7 @@
package com.android.server.input
+import android.animation.ValueAnimator
import android.content.Context
import android.content.ContextWrapper
import android.graphics.Color
@@ -29,8 +30,10 @@
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.InputDevice
+import androidx.test.annotation.UiThreadTest
import androidx.test.core.app.ApplicationProvider
-import com.android.server.input.KeyboardBacklightController.BRIGHTNESS_VALUE_FOR_LEVEL
+import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL
+import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS
import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS
import org.junit.After
import org.junit.Assert.assertEquals
@@ -63,12 +66,20 @@
.build()
private fun createLight(lightId: Int, lightType: Int): Light =
+ createLight(
+ lightId,
+ lightType,
+ null
+ )
+
+private fun createLight(lightId: Int, lightType: Int, suggestedBrightnessLevels: IntArray?): Light =
Light(
lightId,
"Light $lightId",
1,
lightType,
- Light.LIGHT_CAPABILITY_BRIGHTNESS
+ Light.LIGHT_CAPABILITY_BRIGHTNESS,
+ suggestedBrightnessLevels
)
/**
* Tests for {@link KeyboardBacklightController}.
@@ -99,6 +110,7 @@
private var lightColorMap: HashMap<Int, Int> = HashMap()
private var lastBacklightState: KeyboardBacklightState? = null
private var sysfsNodeChanges = 0
+ private var lastAnimationValues = IntArray(2)
@Before
fun setup() {
@@ -115,8 +127,8 @@
override fun finishWrite(fos: FileOutputStream?, success: Boolean) {}
})
testLooper = TestLooper()
- keyboardBacklightController =
- KeyboardBacklightController(context, native, dataStore, testLooper.looper)
+ keyboardBacklightController = KeyboardBacklightController(context, native, dataStore,
+ testLooper.looper, FakeAnimatorFactory())
InputManagerGlobal.resetInstance(iInputManager)
val inputManager = InputManager(context)
`when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
@@ -125,6 +137,10 @@
val args = it.arguments
lightColorMap.put(args[1] as Int, args[2] as Int)
}
+ `when`(native.getLightColor(anyInt(), anyInt())).thenAnswer {
+ val args = it.arguments
+ lightColorMap.getOrDefault(args[1] as Int, 0)
+ }
lightColorMap.clear()
`when`(native.sysfsNodeChanged(any())).then {
sysfsNodeChanges++
@@ -138,271 +154,225 @@
@Test
fun testKeyboardBacklightIncrementDecrement() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- for (level in 1 until BRIGHTNESS_VALUE_FOR_LEVEL.size) {
- incrementKeyboardBacklight(DEVICE_ID)
- assertEquals(
- "Light value for level $level mismatched",
- Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
- assertEquals(
- "Light value for level $level must be correctly stored in the datastore",
- BRIGHTNESS_VALUE_FOR_LEVEL[level],
- dataStore.getKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID
- ).asInt
- )
+ assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL)
}
-
- // Increment above max level
- incrementKeyboardBacklight(DEVICE_ID)
- assertEquals(
- "Light value for max level mismatched",
- Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
- assertEquals(
- "Light value for max level must be correctly stored in the datastore",
- MAX_BRIGHTNESS,
- dataStore.getKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID
- ).asInt
- )
-
- for (level in BRIGHTNESS_VALUE_FOR_LEVEL.size - 2 downTo 0) {
- decrementKeyboardBacklight(DEVICE_ID)
- assertEquals(
- "Light value for level $level mismatched",
- Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
- assertEquals(
- "Light value for level $level must be correctly stored in the datastore",
- BRIGHTNESS_VALUE_FOR_LEVEL[level],
- dataStore.getKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID
- ).asInt
- )
- }
-
- // Decrement below min level
- decrementKeyboardBacklight(DEVICE_ID)
- assertEquals(
- "Light value for min level mismatched",
- Color.argb(0, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
- assertEquals(
- "Light value for min level must be correctly stored in the datastore",
- 0,
- dataStore.getKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID
- ).asInt
- )
}
@Test
fun testKeyboardWithoutBacklight() {
- val keyboardWithoutBacklight = createKeyboard(DEVICE_ID)
- val keyboardInputLight = createLight(LIGHT_ID, Light.LIGHT_TYPE_INPUT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithoutBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardInputLight))
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithoutBacklight = createKeyboard(DEVICE_ID)
+ val keyboardInputLight = createLight(LIGHT_ID, Light.LIGHT_TYPE_INPUT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithoutBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardInputLight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- incrementKeyboardBacklight(DEVICE_ID)
- assertTrue("Non Keyboard backlights should not change", lightColorMap.isEmpty())
+ incrementKeyboardBacklight(DEVICE_ID)
+ assertTrue("Non Keyboard backlights should not change", lightColorMap.isEmpty())
+ }
}
@Test
fun testKeyboardWithMultipleLight() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- val keyboardInputLight = createLight(SECOND_LIGHT_ID, Light.LIGHT_TYPE_INPUT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(
- listOf(
- keyboardBacklight,
- keyboardInputLight
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ val keyboardInputLight = createLight(SECOND_LIGHT_ID, Light.LIGHT_TYPE_INPUT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(
+ listOf(
+ keyboardBacklight,
+ keyboardInputLight
+ )
)
- )
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- incrementKeyboardBacklight(DEVICE_ID)
- assertEquals("Only keyboard backlights should change", 1, lightColorMap.size)
- assertNotNull("Keyboard backlight should change", lightColorMap[LIGHT_ID])
- assertNull("Input lights should not change", lightColorMap[SECOND_LIGHT_ID])
+ incrementKeyboardBacklight(DEVICE_ID)
+ assertEquals("Only keyboard backlights should change", 1, lightColorMap.size)
+ assertNotNull("Keyboard backlight should change", lightColorMap[LIGHT_ID])
+ assertNull("Input lights should not change", lightColorMap[SECOND_LIGHT_ID])
+ }
}
@Test
fun testRestoreBacklightOnInputDeviceAdded() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- for (level in 1 until BRIGHTNESS_VALUE_FOR_LEVEL.size) {
- dataStore.setKeyboardBacklightBrightness(
+ for (level in 1 until DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size) {
+ dataStore.setKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID,
- BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1
+ )
+
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ keyboardBacklightController.notifyUserActivity()
+ testLooper.dispatchNext()
+ assertEquals(
+ "Keyboard backlight level should be restored to the level saved in the " +
+ "data store",
+ Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
+ lightColorMap[LIGHT_ID]
+ )
+ keyboardBacklightController.onInputDeviceRemoved(DEVICE_ID)
+ }
+ }
+ }
+
+ @Test
+ fun testRestoreBacklightOnInputDeviceChanged() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ dataStore.setKeyboardBacklightBrightness(
+ keyboardWithBacklight.descriptor,
+ LIGHT_ID,
+ MAX_BRIGHTNESS
+ )
+
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ keyboardBacklightController.notifyUserActivity()
+ testLooper.dispatchNext()
+ assertTrue(
+ "Keyboard backlight should not be changed until its added",
+ lightColorMap.isEmpty()
+ )
+
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceChanged(DEVICE_ID)
+ keyboardBacklightController.notifyUserActivity()
+ testLooper.dispatchNext()
+ assertEquals(
+ "Keyboard backlight level should be restored to the level saved in the data store",
+ Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
+ lightColorMap[LIGHT_ID]
+ )
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklight_registerUnregisterListener() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ val maxLevel = DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size - 1
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ // Register backlight listener
+ val listener = KeyboardBacklightListener()
+ keyboardBacklightController.registerKeyboardBacklightListener(listener, 0)
+
+ lastBacklightState = null
+ keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
+ testLooper.dispatchNext()
+
+ assertEquals(
+ "Backlight state device Id should be $DEVICE_ID",
+ DEVICE_ID,
+ lastBacklightState!!.deviceId
+ )
+ assertEquals(
+ "Backlight state brightnessLevel should be 1",
+ 1,
+ lastBacklightState!!.brightnessLevel
+ )
+ assertEquals(
+ "Backlight state maxBrightnessLevel should be $maxLevel",
+ maxLevel,
+ lastBacklightState!!.maxBrightnessLevel
+ )
+ assertEquals(
+ "Backlight state isTriggeredByKeyPress should be true",
+ true,
+ lastBacklightState!!.isTriggeredByKeyPress
+ )
+
+ // Unregister listener
+ keyboardBacklightController.unregisterKeyboardBacklightListener(listener, 0)
+
+ lastBacklightState = null
+ incrementKeyboardBacklight(DEVICE_ID)
+
+ assertNull("Listener should not receive any updates", lastBacklightState)
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklight_userActivity() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ dataStore.setKeyboardBacklightBrightness(
+ keyboardWithBacklight.descriptor,
+ LIGHT_ID,
+ MAX_BRIGHTNESS
)
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchNext()
assertEquals(
- "Keyboard backlight level should be restored to the level saved in the data " +
- "store",
- Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
- lightColorMap[LIGHT_ID]
+ "Keyboard backlight level should be restored to the level saved in the data store",
+ Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
+ lightColorMap[LIGHT_ID]
)
- keyboardBacklightController.onInputDeviceRemoved(DEVICE_ID)
+
+ testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000)
+ testLooper.dispatchNext()
+ assertEquals(
+ "Keyboard backlight level should be turned off after inactivity",
+ 0,
+ lightColorMap[LIGHT_ID]
+ )
}
}
@Test
- fun testRestoreBacklightOnInputDeviceChanged() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- dataStore.setKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID,
- MAX_BRIGHTNESS
- )
-
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- keyboardBacklightController.notifyUserActivity()
- testLooper.dispatchNext()
- assertTrue(
- "Keyboard backlight should not be changed until its added",
- lightColorMap.isEmpty()
- )
-
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- keyboardBacklightController.onInputDeviceChanged(DEVICE_ID)
- keyboardBacklightController.notifyUserActivity()
- testLooper.dispatchNext()
- assertEquals(
- "Keyboard backlight level should be restored to the level saved in the data store",
- Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
- }
-
- @Test
- fun testKeyboardBacklight_registerUnregisterListener() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
-
- // Register backlight listener
- val listener = KeyboardBacklightListener()
- keyboardBacklightController.registerKeyboardBacklightListener(listener, 0)
-
- lastBacklightState = null
- keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
- testLooper.dispatchNext()
-
- assertEquals(
- "Backlight state device Id should be $DEVICE_ID",
- DEVICE_ID,
- lastBacklightState!!.deviceId
- )
- assertEquals(
- "Backlight state brightnessLevel should be " + 1,
- 1,
- lastBacklightState!!.brightnessLevel
- )
- assertEquals(
- "Backlight state maxBrightnessLevel should be " + (BRIGHTNESS_VALUE_FOR_LEVEL.size - 1),
- (BRIGHTNESS_VALUE_FOR_LEVEL.size - 1),
- lastBacklightState!!.maxBrightnessLevel
- )
- assertEquals(
- "Backlight state isTriggeredByKeyPress should be true",
- true,
- lastBacklightState!!.isTriggeredByKeyPress
- )
-
- // Unregister listener
- keyboardBacklightController.unregisterKeyboardBacklightListener(listener, 0)
-
- lastBacklightState = null
- incrementKeyboardBacklight(DEVICE_ID)
-
- assertNull("Listener should not receive any updates", lastBacklightState)
- }
-
- @Test
- fun testKeyboardBacklight_userActivity() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- dataStore.setKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID,
- MAX_BRIGHTNESS
- )
-
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- keyboardBacklightController.notifyUserActivity()
- testLooper.dispatchNext()
- assertEquals(
- "Keyboard backlight level should be restored to the level saved in the data store",
- Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
-
- testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000)
- testLooper.dispatchNext()
- assertEquals(
- "Keyboard backlight level should be turned off after inactivity",
- 0,
- lightColorMap[LIGHT_ID]
- )
- }
-
- @Test
fun testKeyboardBacklight_displayOnOff() {
- val keyboardWithBacklight = createKeyboard(DEVICE_ID)
- val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
- `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
- `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- dataStore.setKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID,
- MAX_BRIGHTNESS
- )
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ dataStore.setKeyboardBacklightBrightness(
+ keyboardWithBacklight.descriptor,
+ LIGHT_ID,
+ MAX_BRIGHTNESS
+ )
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- keyboardBacklightController.handleInteractiveStateChange(true /* isDisplayOn */)
- assertEquals(
- "Keyboard backlight level should be restored to the level saved in the data " +
- "store when display turned on",
- Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ keyboardBacklightController.handleInteractiveStateChange(true /* isDisplayOn */)
+ assertEquals(
+ "Keyboard backlight level should be restored to the level saved in the data " +
+ "store when display turned on",
+ Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
+ lightColorMap[LIGHT_ID]
+ )
- keyboardBacklightController.handleInteractiveStateChange(false /* isDisplayOn */)
- assertEquals(
- "Keyboard backlight level should be turned off after display is turned off",
- 0,
- lightColorMap[LIGHT_ID]
- )
+ keyboardBacklightController.handleInteractiveStateChange(false /* isDisplayOn */)
+ assertEquals(
+ "Keyboard backlight level should be turned off after display is turned off",
+ 0,
+ lightColorMap[LIGHT_ID]
+ )
+ }
}
@Test
@@ -463,6 +433,158 @@
)
}
+ @Test
+ @UiThreadTest
+ fun testKeyboardBacklightAnimation_onChangeLevels() {
+ KeyboardBacklightFlags(animationEnabled = true, customLevelsEnabled = false).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ incrementKeyboardBacklight(DEVICE_ID)
+ assertEquals(
+ "Should start animation from level 0",
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[0],
+ lastAnimationValues[0]
+ )
+ assertEquals(
+ "Should start animation to level 1",
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1],
+ lastAnimationValues[1]
+ )
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklightPreferredLevels() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val suggestedLevels = intArrayOf(0, 22, 63, 135, 196, 255)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
+ suggestedLevels)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
+ suggestedLevels)
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklightPreferredLevels_moreThanMax_shouldUseDefault() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val suggestedLevels = IntArray(MAX_BRIGHTNESS_CHANGE_STEPS + 1) { 10 * (it + 1) }
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
+ suggestedLevels)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
+ DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL)
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklightPreferredLevels_mustHaveZeroAndMaxBrightnessAsBounds() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val suggestedLevels = intArrayOf(22, 63, 135, 196)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
+ suggestedLevels)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ // Framework will add the lowest and maximum levels if not provided via config
+ assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
+ intArrayOf(0, 22, 63, 135, 196, 255))
+ }
+ }
+
+ @Test
+ fun testKeyboardBacklightPreferredLevels_dropsOutOfBoundsLevels() {
+ KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
+ val keyboardWithBacklight = createKeyboard(DEVICE_ID)
+ val suggestedLevels = intArrayOf(22, 63, 135, 400, 196, 1000)
+ val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
+ suggestedLevels)
+ `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
+ `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+
+ // Framework will drop out of bound levels in the config
+ assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
+ intArrayOf(0, 22, 63, 135, 196, 255))
+ }
+ }
+
+ private fun assertIncrementDecrementForLevels(
+ device: InputDevice,
+ light: Light,
+ expectedLevels: IntArray
+ ) {
+ val deviceId = device.id
+ val lightId = light.id
+ for (level in 1 until expectedLevels.size) {
+ incrementKeyboardBacklight(deviceId)
+ assertEquals(
+ "Light value for level $level mismatched",
+ Color.argb(expectedLevels[level], 0, 0, 0),
+ lightColorMap[lightId]
+ )
+ assertEquals(
+ "Light value for level $level must be correctly stored in the datastore",
+ expectedLevels[level],
+ dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
+ )
+ }
+
+ // Increment above max level
+ incrementKeyboardBacklight(deviceId)
+ assertEquals(
+ "Light value for max level mismatched",
+ Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
+ lightColorMap[lightId]
+ )
+ assertEquals(
+ "Light value for max level must be correctly stored in the datastore",
+ MAX_BRIGHTNESS,
+ dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
+ )
+
+ for (level in expectedLevels.size - 2 downTo 0) {
+ decrementKeyboardBacklight(deviceId)
+ assertEquals(
+ "Light value for level $level mismatched",
+ Color.argb(expectedLevels[level], 0, 0, 0),
+ lightColorMap[lightId]
+ )
+ assertEquals(
+ "Light value for level $level must be correctly stored in the datastore",
+ expectedLevels[level],
+ dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
+ )
+ }
+
+ // Decrement below min level
+ decrementKeyboardBacklight(deviceId)
+ assertEquals(
+ "Light value for min level mismatched",
+ Color.argb(0, 0, 0, 0),
+ lightColorMap[lightId]
+ )
+ assertEquals(
+ "Light value for min level must be correctly stored in the datastore",
+ 0,
+ dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
+ )
+ }
+
inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() {
override fun onBrightnessChanged(
deviceId: Int,
@@ -496,4 +618,26 @@
val maxBrightnessLevel: Int,
val isTriggeredByKeyPress: Boolean
)
+
+ private inner class KeyboardBacklightFlags constructor(
+ animationEnabled: Boolean,
+ customLevelsEnabled: Boolean
+ ) : AutoCloseable {
+ init {
+ InputFeatureFlagProvider.setKeyboardBacklightAnimationEnabled(animationEnabled)
+ InputFeatureFlagProvider.setKeyboardBacklightCustomLevelsEnabled(customLevelsEnabled)
+ }
+
+ override fun close() {
+ InputFeatureFlagProvider.clearOverrides()
+ }
+ }
+
+ private inner class FakeAnimatorFactory : KeyboardBacklightController.AnimatorFactory {
+ override fun makeIntAnimator(from: Int, to: Int): ValueAnimator {
+ lastAnimationValues[0] = from
+ lastAnimationValues[1] = to
+ return ValueAnimator.ofInt(from, to)
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 676bfb0..2015ae9 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -39,6 +39,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER;
import static java.util.Collections.unmodifiableMap;
@@ -59,7 +60,7 @@
class ShortcutKeyTestBase {
TestPhoneWindowManager mPhoneWindowManager;
- final Context mContext = getInstrumentation().getTargetContext();
+ final Context mContext = spy(getInstrumentation().getTargetContext());
/** Modifier key to meta state */
private static final Map<Integer, Integer> MODIFIER;
diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
new file mode 100644
index 0000000..fe8017e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
@@ -0,0 +1,102 @@
+/*
+ * 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.policy;
+
+import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+/**
+ * Test class for stem key gesture.
+ *
+ * Build/Install/Run:
+ * atest WmTests:StemKeyGestureTests
+ */
+public class StemKeyGestureTests extends ShortcutKeyTestBase {
+ @Mock private Resources mResources;
+
+ /**
+ * Stem single key should not launch behavior during set up.
+ */
+ @Test
+ public void stemSingleKey_duringSetup_doNothing() {
+ stemKeySetup(
+ () -> overrideBehavior(
+ com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior,
+ SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS));
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(false);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertNotOpenAllAppView();
+ }
+
+ /**
+ * Stem single key should launch all app after set up.
+ */
+ @Test
+ public void stemSingleKey_AfterSetup_openAllApp() {
+ stemKeySetup(
+ () -> overrideBehavior(
+ com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior,
+ SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS));
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertOpenAllAppView();
+ }
+
+ private void stemKeySetup(Runnable behaviorOverrideRunnable) {
+ super.tearDown();
+ setupResourcesMock();
+ behaviorOverrideRunnable.run();
+ super.setUp();
+ }
+
+ private void setupResourcesMock() {
+ Resources realResources = mContext.getResources();
+
+ mResources = Mockito.mock(Resources.class);
+ doReturn(mResources).when(mContext).getResources();
+
+ doAnswer(invocation -> realResources.getXml((Integer) invocation.getArguments()[0]))
+ .when(mResources).getXml(anyInt());
+ doAnswer(invocation -> realResources.getString((Integer) invocation.getArguments()[0]))
+ .when(mResources).getString(anyInt());
+ doAnswer(invocation -> realResources.getBoolean((Integer) invocation.getArguments()[0]))
+ .when(mResources).getBoolean(anyInt());
+ }
+
+ private void overrideBehavior(int resId, int expectedBehavior) {
+ doReturn(expectedBehavior).when(mResources).getInteger(eq(resId));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index d383024..af48cbd 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -16,6 +16,7 @@
package com.android.server.policy;
+import static android.os.Build.HW_TIMEOUT_MULTIPLIER;
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.STATE_ON;
@@ -43,8 +44,11 @@
import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.withSettings;
@@ -64,6 +68,7 @@
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.Vibrator;
import android.service.dreams.DreamManagerInternal;
import android.telecom.TelecomManager;
@@ -79,6 +84,7 @@
import com.android.server.input.InputManagerInternal;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -100,6 +106,8 @@
class TestPhoneWindowManager {
private static final long SHORTCUT_KEY_DELAY_MILLIS = 150;
+ private static final long TEST_SINGLE_KEY_DELAY_MILLIS
+ = SingleKeyGestureDetector.MULTI_PRESS_TIMEOUT + 1000L * HW_TIMEOUT_MULTIPLIER;
private PhoneWindowManager mPhoneWindowManager;
private Context mContext;
@@ -134,6 +142,8 @@
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+ @Mock private KeyguardServiceDelegate mKeyguardServiceDelegate;
+
private StaticMockitoSession mMockitoSession;
private HandlerThread mHandlerThread;
private Handler mHandler;
@@ -151,6 +161,10 @@
Supplier<GlobalActions> getGlobalActionsFactory() {
return () -> mGlobalActions;
}
+
+ KeyguardServiceDelegate getKeyguardServiceDelegate() {
+ return mKeyguardServiceDelegate;
+ }
}
TestPhoneWindowManager(Context context) {
@@ -158,12 +172,12 @@
mHandlerThread = new HandlerThread("fake window manager");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
- mHandler.runWithScissors(()-> setUp(context), 0 /* timeout */);
+ mContext = mockingDetails(context).isSpy() ? context : spy(context);
+ mHandler.runWithScissors(this::setUp, 0 /* timeout */);
}
- private void setUp(Context context) {
+ private void setUp() {
mPhoneWindowManager = spy(new PhoneWindowManager());
- mContext = spy(context);
// Use stubOnly() to reduce memory usage if it doesn't need verification.
final MockSettings spyStubOnly = withSettings().stubOnly()
@@ -251,6 +265,7 @@
overrideLaunchAccessibility();
doReturn(false).when(mPhoneWindowManager).keyguardOn();
doNothing().when(mContext).startActivityAsUser(any(), any());
+ doNothing().when(mContext).startActivityAsUser(any(), any(), any());
Mockito.reset(mContext);
}
@@ -381,6 +396,14 @@
doNothing().when(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
}
+ void overrideIsUserSetupComplete(boolean isCompleted) {
+ doReturn(isCompleted).when(mPhoneWindowManager).isUserSetupComplete();
+ }
+
+ void setKeyguardServiceDelegateIsShowing(boolean isShowing) {
+ doReturn(isShowing).when(mKeyguardServiceDelegate).isShowing();
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
@@ -514,4 +537,18 @@
waitForIdle();
verify(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
}
+
+ void assertOpenAllAppView() {
+ waitForIdle();
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, timeout(TEST_SINGLE_KEY_DELAY_MILLIS))
+ .startActivityAsUser(intentCaptor.capture(), isNull(), any(UserHandle.class));
+ Assert.assertEquals(Intent.ACTION_ALL_APPS, intentCaptor.getValue().getAction());
+ }
+
+ void assertNotOpenAllAppView() {
+ waitForIdle();
+ verify(mContext, after(TEST_SINGLE_KEY_DELAY_MILLIS).never())
+ .startActivityAsUser(any(Intent.class), any(), any(UserHandle.class));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index cb984f8..77e944f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3329,7 +3329,7 @@
// app1 requests IME visible.
app1.setRequestedVisibleTypes(ime(), ime());
- mDisplayContent.getInsetsStateController().onInsetsModified(app1);
+ mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1);
// Verify app1's IME insets is visible and app2's IME insets frozen flag set.
assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
@@ -3398,7 +3398,7 @@
assertFalse(activity2.mImeInsetsFrozenUntilStartInput);
app1.setRequestedVisibleTypes(ime());
- controller.onInsetsModified(app1);
+ controller.onRequestedVisibleTypesChanged(app1);
// Expect all activities in split-screen will get IME insets visible state
assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2b589bf..d179338 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1702,6 +1702,9 @@
@Test
public void testRecordActivityMovementBeforeDeliverToTop() {
+ // Mock recents as task is only marked to be in recents
+ mAtm.mTaskSupervisor.setRecentTasks(mock(RecentTasks.class));
+
final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build();
final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index b0609dd..dd90e04 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -182,6 +182,44 @@
dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
}
+ @Test
+ public void testChooseNavigationBackgroundWindow() {
+ final WindowState drawBarWin = createOpaqueFullscreen(false);
+ final WindowState nonDrawBarWin = createDimmingDialogWindow(true);
+
+ final WindowState visibleIme = createInputMethodWindow(true, true, false);
+ final WindowState invisibleIme = createInputMethodWindow(false, true, false);
+ final WindowState nonDrawBarIme = createInputMethodWindow(true, false, false);
+
+ assertEquals(drawBarWin, DisplayPolicy.chooseNavigationBackgroundWindow(
+ drawBarWin, null, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ null, null, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ nonDrawBarWin, null, NAV_BAR_BOTTOM));
+
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationBackgroundWindow(
+ drawBarWin, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationBackgroundWindow(
+ null, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationBackgroundWindow(
+ nonDrawBarWin, visibleIme, NAV_BAR_BOTTOM));
+
+ assertEquals(drawBarWin, DisplayPolicy.chooseNavigationBackgroundWindow(
+ drawBarWin, invisibleIme, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ null, invisibleIme, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ nonDrawBarWin, invisibleIme, NAV_BAR_BOTTOM));
+
+ assertEquals(drawBarWin, DisplayPolicy.chooseNavigationBackgroundWindow(
+ drawBarWin, nonDrawBarIme, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ null, nonDrawBarIme, NAV_BAR_BOTTOM));
+ assertNull(DisplayPolicy.chooseNavigationBackgroundWindow(
+ nonDrawBarWin, nonDrawBarIme, NAV_BAR_BOTTOM));
+ }
+
@SetupWindows(addWindows = W_NAVIGATION_BAR)
@Test
public void testUpdateLightNavigationBarLw() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index a8fc25f..204cbf7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -370,7 +370,7 @@
mAppWindow.setRequestedVisibleTypes(
navigationBars() | statusBars(), navigationBars() | statusBars());
- policy.onInsetsModified(mAppWindow);
+ policy.onRequestedVisibleTypesChanged(mAppWindow);
waitUntilWindowAnimatorIdle();
controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index d7e736d..114796d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -192,17 +192,16 @@
// This can be the IME z-order target while app cannot be the IME z-order target.
// This is also the only IME control target in this test, so IME won't be invisible caused
// by the control-target change.
- mDisplayContent.updateImeInputAndControlTarget(
- createWindow(null, TYPE_APPLICATION, "base"));
+ final WindowState base = createWindow(null, TYPE_APPLICATION, "base");
+ mDisplayContent.updateImeInputAndControlTarget(base);
// Make IME and stay visible during the test.
mImeWindow.setHasSurface(true);
getController().getOrCreateSourceProvider(ID_IME, ime())
.setWindowContainer(mImeWindow, null, null);
- getController().onImeControlTargetChanged(
- mDisplayContent.getImeInputTarget().getWindowState());
- mDisplayContent.getImeInputTarget().getWindowState().setRequestedVisibleTypes(ime(), ime());
- getController().onInsetsModified(mDisplayContent.getImeInputTarget().getWindowState());
+ getController().onImeControlTargetChanged(base);
+ base.setRequestedVisibleTypes(ime(), ime());
+ getController().onRequestedVisibleTypesChanged(base);
// Send our spy window (app) into the system so that we can detect the invocation.
final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
@@ -485,7 +484,7 @@
mDisplayContent.updateImeInputAndControlTarget(app);
app.setRequestedVisibleTypes(ime(), ime());
- getController().onInsetsModified(app);
+ getController().onRequestedVisibleTypesChanged(app);
assertTrue(ime.getControllableInsetProvider().getSource().isVisible());
getController().updateAboveInsetsState(true /* notifyInsetsChange */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 7d507e9..34a13bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -38,6 +38,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
@@ -461,7 +462,7 @@
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
WindowInsets.Type.navigationBars());
- taskbar.setInsetsRoundedCornerFrame(true);
+ taskbar.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
final Rect opaqueBounds = new Rect(0, 0, 500, 300);
doReturn(opaqueBounds).when(mActivity).getBounds();
@@ -505,7 +506,7 @@
public void testGetCropBoundsIfNeeded_appliesCrop() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
WindowInsets.Type.navigationBars());
- taskbar.setInsetsRoundedCornerFrame(true);
+ taskbar.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
// Apply crop if taskbar is expanded
@@ -528,7 +529,7 @@
public void testGetCropBoundsIfNeeded_appliesCropWithSizeCompatScaling() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
WindowInsets.Type.navigationBars());
- taskbar.setInsetsRoundedCornerFrame(true);
+ taskbar.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
final float scaling = 2.0f;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 0ccb0d0..b02b774 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -49,10 +49,12 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
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 java.lang.Integer.MAX_VALUE;
@@ -1139,6 +1141,40 @@
}
@Test
+ public void addTask_taskAlreadyInRecentsMovedToTop_callsTaskNotificationController() {
+ final Task firstTask = createTaskBuilder(".Task").build();
+ final Task secondTask = createTaskBuilder(".Task2").build();
+
+ mRecentTasks.add(firstTask);
+ mRecentTasks.add(secondTask);
+
+ TaskChangeNotificationController controller =
+ mAtm.getTaskChangeNotificationController();
+ clearInvocations(controller);
+
+ // Add firstTask back to top
+ mRecentTasks.add(firstTask);
+ verify(controller).notifyTaskListUpdated();
+ }
+
+ @Test
+ public void addTask_taskAlreadyInRecentsOnTop_doesNotNotify() {
+ final Task firstTask = createTaskBuilder(".Task").build();
+ final Task secondTask = createTaskBuilder(".Task2").build();
+
+ mRecentTasks.add(firstTask);
+ mRecentTasks.add(secondTask);
+
+ TaskChangeNotificationController controller =
+ mAtm.getTaskChangeNotificationController();
+ clearInvocations(controller);
+
+ // Add secondTask to top again
+ mRecentTasks.add(secondTask);
+ verifyZeroInteractions(controller);
+ }
+
+ @Test
public void removeTask_callsTaskNotificationController() {
final Task task = createTaskBuilder(".Task").build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 2dd34eb..d91be16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -30,6 +30,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
+import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
@@ -3483,7 +3484,7 @@
final InsetsSource navSource = new InsetsSource(
InsetsSource.createId(null, 0, navigationBars()), navigationBars());
- navSource.setInsetsRoundedCornerFrame(true);
+ navSource.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
navSource.setFrame(new Rect(0, screenHeight - taskbarHeight, screenWidth, screenHeight));
mActivity.mWmService.mLetterboxConfiguration.setLetterboxActivityCornersRadius(15);
@@ -3531,7 +3532,7 @@
final InsetsSource navSource = new InsetsSource(
InsetsSource.createId(null, 0, navigationBars()), navigationBars());
- navSource.setInsetsRoundedCornerFrame(true);
+ navSource.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
// Immersive activity has transient navbar
navSource.setVisible(!immersive);
navSource.setFrame(new Rect(0, screenHeight - taskbarHeight, screenWidth, screenHeight));
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 4ba538e..4c55f7f 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -23,14 +23,49 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-android_test {
- name: "FlickerTests",
+filegroup {
+ name: "FlickerTestsBase-src",
+ srcs: ["src/com/android/server/wm/flicker/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsAppClose-src",
+ srcs: ["src/**/close/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsActivityEmbedding-src",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
+ "src/**/activityembedding/*.kt",
+ "src/**/activityembedding/close/*.kt",
+ "src/**/activityembedding/rotation/*.kt",
],
- manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+}
+
+filegroup {
+ name: "FlickerTestsIme-src",
+ srcs: ["src/**/ime/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunch-src",
+ srcs: ["src/**/launch/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsQuickswitch-src",
+ srcs: ["src/**/quickswitch/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsRotation-src",
+ srcs: ["src/**/rotation/*.kt"],
+}
+
+java_defaults {
+ name: "FlickerTestsDefault",
+ manifest: "manifests/AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -42,16 +77,98 @@
"androidx.test.ext.junit",
"flickertestapplib",
"flickerlib",
- "flickerlib-apphelpers",
"flickerlib-helpers",
- "truth-prebuilt",
- "launcher-helper-lib",
- "launcher-aosp-tapl",
"platform-test-annotations",
- "wm-flicker-window-extensions",
+ "wm-flicker-common-app-helpers",
],
data: [
":FlickerTestApp",
+ "trace_config/*",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsOther",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestOther.xml"],
+ package_name: "com.android.server.wm.flicker",
+ instrumentation_target_package: "com.android.server.wm.flicker",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ exclude_srcs: [
+ ":FlickerTestsAppClose-src",
+ ":FlickerTestsIme-src",
+ ":FlickerTestsAppLaunch-src",
+ ":FlickerTestsQuickswitch-src",
+ ":FlickerTestsRotation-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsAppClose",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestAppClose.xml"],
+ package_name: "com.android.server.wm.flicker.close",
+ instrumentation_target_package: "com.android.server.wm.flicker.close",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsAppClose-src",
+ ],
+ exclude_srcs: [
+ ":FlickerTestsActivityEmbedding-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsIme",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestIme.xml"],
+ package_name: "com.android.server.wm.flicker.ime",
+ instrumentation_target_package: "com.android.server.wm.flicker.ime",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsIme-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
+ package_name: "com.android.server.wm.flicker.launch",
+ instrumentation_target_package: "com.android.server.wm.flicker.launch",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsAppLaunch-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsQuickswitch",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestQuickswitch.xml"],
+ package_name: "com.android.server.wm.flicker.rotation",
+ instrumentation_target_package: "com.android.server.wm.flicker.rotation",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsQuickswitch-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsRotation",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestRotation.xml"],
+ package_name: "com.android.server.wm.flicker.rotation",
+ instrumentation_target_package: "com.android.server.wm.flicker.rotation",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsRotation-src",
+ ],
+ exclude_srcs: [
+ ":FlickerTestsActivityEmbedding-src",
],
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
deleted file mode 100644
index 32ff243..0000000
--- a/tests/FlickerTests/AndroidTest.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright 2018 Google Inc. All Rights Reserved.
- -->
-<configuration description="Runs WindowManager Flicker Tests">
- <option name="test-tag" value="FlickerTests" />
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- keeps the screen on during tests -->
- <option name="screen-always-on" value="on" />
- <!-- prevents the phone from restarting -->
- <option name="force-skip-system-props" value="true" />
- <!-- set WM tracing verbose level to all -->
- <option name="run-command" value="cmd window tracing level all" />
- <!-- set WM tracing to frame (avoid incomplete states) -->
- <option name="run-command" value="cmd window tracing frame" />
- <!-- ensure lock screen mode is swipe -->
- <option name="run-command" value="locksettings set-disabled false" />
- <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
- <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
- <!-- restart launcher to activate TAPL -->
- <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
- <!-- Ensure output directory is empty at the start -->
- <option name="run-command" value="rm -rf /sdcard/flicker" />
- <!-- Increase trace size: 20mb for WM and 80mb for SF -->
- <option name="run-command" value="cmd window tracing size 20480" />
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
- <option name="run-command" value="settings put system show_touches 1" />
- <option name="run-command" value="settings put system pointer_location 1" />
- <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
- <option name="teardown-command" value="settings delete system show_touches" />
- <option name="teardown-command" value="settings delete system pointer_location" />
- <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="FlickerTests.apk"/>
- <option name="test-file-name" value="FlickerTestApp.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="com.android.server.wm.flicker"/>
- <option name="shell-timeout" value="6600s" />
- <option name="test-timeout" value="6600s" />
- <option name="hidden-api-checks" value="false" />
- </test>
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/flicker" />
- <option name="collect-on-run-ended-only" value="true" />
- <option name="clean-up" value="true" />
- </metrics_collector>
-</configuration>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AndroidTestTemplate.xml
new file mode 100644
index 0000000..ec01317
--- /dev/null
+++ b/tests/FlickerTests/AndroidTestTemplate.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager {MODULE}">
+ <option name="test-tag" value="FlickerTests" />
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
+ <!-- ensure lock screen mode is swipe -->
+ <option name="run-command" value="locksettings set-disabled false" />
+ <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
+ <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ <!-- Ensure output directory is empty at the start -->
+ <option name="run-command" value="rm -rf /sdcard/flicker" />
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480" />
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="run-command" value="settings put system show_touches 1" />
+ <option name="run-command" value="settings put system pointer_location 1" />
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard" />
+ <option name="teardown-command" value="settings delete system show_touches" />
+ <option name="teardown-command" value="settings delete system pointer_location" />
+ <option name="teardown-command"
+ value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="{MODULE}.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk" />
+ </target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file"
+ key="trace_config.textproto"
+ value="/data/misc/perfetto-traces/trace_config.textproto"
+ />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="{PACKAGE}"/>
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6600s" />
+ <option name="hidden-api-checks" value="false" />
+ <option name="device-listeners" value="android.device.collectors.PerfettoListener" />
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg"
+ key="perfetto_config_file"
+ value="trace_config.textproto"
+ />
+ <option name="instrumentation-arg" key="per_run" value="true" />
+ </test>
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+ <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+ <option name="collect-on-run-ended-only" value="false" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/manifests/AndroidManifest.xml
similarity index 70%
rename from tests/FlickerTests/AndroidManifest.xml
rename to tests/FlickerTests/manifests/AndroidManifest.xml
index 462f91b..de8a3c6 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/manifests/AndroidManifest.xml
@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
+<!--
+ ~ 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.
+ -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker">
@@ -47,9 +48,4 @@
<uses-library android:name="android.test.runner"/>
<uses-library android:name="androidx.window.extensions" android:required="false"/>
</application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppClose.xml b/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
new file mode 100644
index 0000000..4cdcb90
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.close">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.close"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml b/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
new file mode 100644
index 0000000..659a745
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.launch">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.launch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestIme.xml b/tests/FlickerTests/manifests/AndroidManifestIme.xml
new file mode 100644
index 0000000..abd03af
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestIme.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.ime">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.ime"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/manifests/AndroidManifestOther.xml
new file mode 100644
index 0000000..47749b8
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestOther.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml b/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
new file mode 100644
index 0000000..203035d
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.quickswitch">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.quickswitch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestRotation.xml b/tests/FlickerTests/manifests/AndroidManifestRotation.xml
new file mode 100644
index 0000000..2852cf2
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestRotation.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.rotation">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.rotation"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
+</manifest>
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
new file mode 100644
index 0000000..c0c738b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.datatypes.Rect
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test closing a secondary activity in a split.
+ *
+ * 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`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseSecondaryActivityInSplitTest(flicker: FlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
+
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+ // Launches fullscreen A.
+ testApp.launchViaIntent(wmHelper)
+ // Launches a split A|B and waits for both activities to show.
+ testApp.launchSecondaryActivity(wmHelper)
+ // Get fullscreen bounds
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds ?:
+ error("Can't get display bounds")
+ }
+ transitions {
+ // Finish secondary activity B.
+ testApp.finishSecondaryActivity(wmHelper)
+ // Expect the main activity A to expand into fullscreen.
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+ teardown {
+ tapl.goHome()
+ testApp.exit(wmHelper)
+ }
+ }
+
+ /** Main activity is always visible and becomes fullscreen in the end. */
+ @Presubmit
+ @Test
+ fun mainActivityWindowBecomesFullScreen() {
+ flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ flicker.assertWmEnd {
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .coversExactly(startDisplayBounds)
+ }
+ }
+
+ /** Main activity surface is animated from split to fullscreen. */
+ @Presubmit
+ @Test
+ fun mainActivityLayerIsAlwaysVisible() {
+ flicker.assertLayers {
+ isVisible(
+ ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT.or(
+ ComponentNameMatcher.TRANSITION_SNAPSHOT
+ )
+ )
+ }
+ flicker.assertLayersEnd {
+ isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .isInvisible(ComponentNameMatcher.TRANSITION_SNAPSHOT)
+ }
+ }
+
+ /** Secondary activity should destroy and become invisible. */
+ @Presubmit
+ @Test
+ fun secondaryActivityWindowFinishes() {
+ flicker.assertWm {
+ contains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .notContains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun secondaryActivityLayerFinishes() {
+ flicker.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+ }
\ No newline at end of file
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
new file mode 100644
index 0000000..39ae8e2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import com.android.server.wm.flicker.rotation.RotationTransition
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Tests rotating two activities in an Activity Embedding split.
+ *
+ * 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`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class RotateSplitNoChangeTest(flicker: FlickerTest) : RotationTransition(flicker) {
+
+ override val testApp = ActivityEmbeddingAppHelper(instrumentation)
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
+ setup {
+ testApp.launchViaIntent(wmHelper)
+ testApp.launchSecondaryActivity(wmHelper)
+ }
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
+ * flicker, and disappears before the transition is complete
+ */
+ @Presubmit
+ @Test
+ fun rotationLayerAppearsAndVanishes() {
+ flicker.assertLayers {
+ this.isVisible(testApp)
+ .then()
+ .isVisible(ComponentNameMatcher.ROTATION)
+ .then()
+ .isVisible(testApp)
+ .isInvisible(ComponentNameMatcher.ROTATION)
+ }
+ }
+
+ /**
+ * Overrides inherited assertion because in AE Split, the main and secondary activity are separate
+ * layers, each covering up exactly half of the display.
+ */
+ @Presubmit
+ @Test
+ override fun appLayerRotates_StartingPos() {
+ flicker.assertLayersStart {
+ this.entry.displays.map { display ->
+ val leftLayerRegion = this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ // Compare dimensions of two splits, given we're using default split attributes,
+ // both activities take up the same visible size on the display.
+ check{"height"}.that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
+ check{"width"}.that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
+ leftLayerRegion.notOverlaps(rightLayerRegion.region)
+ // Layers of two activities sum to be fullscreen size on display.
+ leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /**
+ * Verifies dimensions of both split activities hold their invariance after transition too.
+ */
+ @Presubmit
+ @Test
+ override fun appLayerRotates_EndingPos() {
+ flicker.assertLayersEnd {
+ this.entry.displays.map { display ->
+ val leftLayerRegion = this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ check{"height"}.that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
+ check{"width"}.that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
+ leftLayerRegion.notOverlaps(rightLayerRegion.region)
+ leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /** Both activities in split should remain visible during rotation. */
+ @Presubmit
+ @Test
+ fun bothActivitiesAreAlwaysVisible() {
+ flicker.assertWm {
+ isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ flicker.assertWm {
+ isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.rotationTests()
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index daecfe7..e019b2b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -60,6 +60,24 @@
}
/**
+ * Clicks the button to finishes the secondary activity launched through
+ * [launchSecondaryActivity], waits for the main activity to resume.
+ */
+ fun finishSecondaryActivity(wmHelper: WindowManagerStateHelper) {
+ val finishButton =
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "finish_secondary_activity_button")),
+ FIND_TIMEOUT
+ )
+ require(finishButton != null) { "Can't find finish secondary activity button on screen." }
+ finishButton.click()
+ wmHelper
+ .StateSyncBuilder()
+ .withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
+ .waitForAndVerify()
+ }
+
+ /**
* Clicks the button to launch the placeholder primary activity, which should launch the
* placeholder secondary activity based on the placeholder rule.
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTestCfArm.kt
deleted file mode 100644
index 8b89a8b..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTestCfArm.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.launch
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ActivitiesTransitionTestCfArm(flicker: FlickerTest) : ActivitiesTransitionTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index e6594c9..a87fae8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -57,7 +57,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ActivitiesTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ActivityTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
similarity index 94%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
index ac05c76..85344a1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
@@ -27,7 +27,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppAfterCameraTestCfArm(flicker: FlickerTest) : OpenAppAfterCameraTest(flicker) {
+class ActivityTransitionTestCfArm(flicker: FlickerTest) : ActivityTransitionTest(flicker) {
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 3a80c66..5752065 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -55,7 +55,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppColdFromIcon(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIconColdTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
index d33a272..d453c1a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
@@ -32,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdFromIconCfArm(flicker: FlickerTest) : OpenAppColdFromIcon(flicker) {
+class OpenAppFromIconColdTestCfArm(flicker: FlickerTest) : OpenAppFromIconColdTest(flicker) {
@Test
@FlakyTest
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index 549183f..e747315 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -38,7 +38,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppAfterCameraTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIntentColdAfterCameraTest(flicker: FlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
private val cameraApp = CameraAppHelper(instrumentation)
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
similarity index 92%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
copy to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
index ac05c76..177ad7d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
@@ -27,7 +27,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppAfterCameraTestCfArm(flicker: FlickerTest) : OpenAppAfterCameraTest(flicker) {
+class OpenAppFromIntentColdAfterCameraTestCfArm(flicker: FlickerTest) :
+ OpenAppFromIntentColdAfterCameraTest(flicker) {
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
similarity index 96%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index 26f88d2..f45f728 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -58,7 +58,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppColdTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIntentColdTest(flicker: FlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
similarity index 94%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
index d9a99da..0d695f3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
@@ -31,7 +31,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdTestCfArm(flicker: FlickerTest) : OpenAppColdTest(flicker) {
+class OpenAppFromIntentColdTestCfArm(flicker: FlickerTest) : OpenAppFromIntentColdTest(flicker) {
@FlakyTest(bugId = 273696733)
@Test
override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
similarity index 96%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index 3385830..a42bff5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -58,7 +58,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppWarmTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIntentWarmTest(flicker: FlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
similarity index 94%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
index d8b38b3..b6ffcb3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
@@ -29,7 +29,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppWarmTestCfArm(flicker: FlickerTest) : OpenAppWarmTest(flicker) {
+class OpenAppFromIntentWarmTestCfArm(flicker: FlickerTest) : OpenAppFromIntentWarmTest(flicker) {
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
similarity index 96%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
index b21777b..fd42726 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
@@ -44,8 +44,8 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-open class OpenAppFromLockNotificationCold(flicker: FlickerTest) :
- OpenAppFromNotificationCold(flicker) {
+open class OpenAppFromLockscreenNotificationColdTest(flicker: FlickerTest) :
+ OpenAppFromNotificationColdTest(flicker) {
override val openingNotificationsFromLockScreen = true
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
index ec92ca6..fd051d5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -46,7 +46,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromLockNotificationWarm(flicker: FlickerTest) : OpenAppFromNotificationWarm(flicker) {
+class OpenAppFromLockscreenNotificationWarmTest(flicker: FlickerTest) :
+ OpenAppFromNotificationWarmTest(flicker) {
override val openingNotificationsFromLockScreen = true
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index 009d617..37afa8d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -37,6 +37,8 @@
* Test cold launching an app from a notification from the lock screen when there is an app overlaid
* on the lock screen.
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppFromLockNotificationWithLockOverlayApp`
*/
@RequiresDevice
@@ -44,8 +46,8 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-class OpenAppFromLockNotificationWithLockOverlayApp(flicker: FlickerTest) :
- OpenAppFromLockNotificationCold(flicker) {
+class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: FlickerTest) :
+ OpenAppFromLockscreenNotificationColdTest(flicker) {
private val showWhenLockedApp = ShowWhenLockedAppHelper(instrumentation)
// Although we are technically still locked here, the overlay app means we should open the
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
index eae9ca1..30c3ec2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
@@ -28,7 +28,7 @@
import org.junit.Test
/** Base class for app launch tests from lock screen */
-abstract class OpenAppFromLockTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
+abstract class OpenAppFromLockscreenTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 1383ae3..924d03f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -63,7 +63,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppNonResizeableTest(flicker: FlickerTest) : OpenAppFromLockTransition(flicker) {
+open class OpenAppFromLockscreenViaIntentTest(flicker: FlickerTest) :
+ OpenAppFromLockscreenTransition(flicker) {
override val testApp = NonResizeableAppHelper(instrumentation)
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
index 7bcb910..d873ec5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
@@ -35,8 +35,6 @@
/**
* Test cold launching an app from a notification.
*
- * This test assumes the device doesn't have AOD enabled
- *
* To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
*/
@RequiresDevice
@@ -44,8 +42,8 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-open class OpenAppFromNotificationCold(flicker: FlickerTest) :
- OpenAppFromNotificationWarm(flicker) {
+open class OpenAppFromNotificationColdTest(flicker: FlickerTest) :
+ OpenAppFromNotificationWarmTest(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
similarity index 93%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
index 8b4a613..fb2a48c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
@@ -29,8 +29,8 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-class OpenAppFromNotificationColdCfArm(flicker: FlickerTest) :
- OpenAppFromNotificationCold(flicker) {
+class OpenAppFromNotificationColdTestCfArm(flicker: FlickerTest) :
+ OpenAppFromNotificationColdTest(flicker) {
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmCfArm.kt
deleted file mode 100644
index 43d28fa..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmCfArm.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.launch
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromNotificationWarmCfArm(flicker: FlickerTest) :
- OpenAppFromNotificationWarm(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
index 425e674d..99668ec 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
@@ -47,15 +47,13 @@
/**
* Test cold launching an app from a notification.
*
- * This test assumes the device doesn't have AOD enabled
- *
* To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromNotificationWarm(flicker: FlickerTest) : OpenAppTransition(flicker) {
+open class OpenAppFromNotificationWarmTest(flicker: FlickerTest) : OpenAppTransition(flicker) {
override val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
open val openingNotificationsFromLockScreen = false
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
similarity index 92%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
copy to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
index ac05c76..2a2597e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
@@ -27,7 +27,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppAfterCameraTestCfArm(flicker: FlickerTest) : OpenAppAfterCameraTest(flicker) {
+class OpenAppFromNotificationWarmTestCfArm(flicker: FlickerTest) :
+ OpenAppFromNotificationWarmTest(flicker) {
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index ae9ca80..6ee8ae6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -60,7 +60,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) :
+class OpenCameraFromHomeOnDoubleClickPowerButtonTest(flicker: FlickerTest) :
OpenAppFromLauncherTransition(flicker) {
private val cameraApp = CameraAppHelper(instrumentation)
override val testApp: StandardAppHelper
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
index 3a02cad..f0dfdfc 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -20,5 +20,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
-
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
new file mode 100644
index 0000000..239aba5
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/secondary_activity_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/finish_secondary_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:text="Finish" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
index 00f4c25..6e78750 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
@@ -16,15 +16,28 @@
package com.android.server.wm.flicker.testapp;
+import android.app.Activity;
import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
/**
* Activity to be used as the secondary activity to split with
* {@link ActivityEmbeddingMainActivity}.
*/
-public class ActivityEmbeddingSecondaryActivity extends ActivityEmbeddingBaseActivity {
+public class ActivityEmbeddingSecondaryActivity extends Activity {
+
@Override
- int getBackgroundColor() {
- return Color.YELLOW;
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_embedding_secondary_activity_layout);
+ findViewById(R.id.secondary_activity_layout).setBackgroundColor(Color.YELLOW);
+ findViewById(R.id.finish_secondary_activity_button).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ });
}
}
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/trace_config/trace_config.textproto
new file mode 100644
index 0000000..c9a35ac
--- /dev/null
+++ b/tests/FlickerTests/trace_config/trace_config.textproto
@@ -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.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 2500
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 30000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers: {
+ size_kb: 63488
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ # polled per-process memory counters and process/thread names.
+ # If you don't want the polled counters, remove the "process_stats_config"
+ # section, but keep the data source itself as it still provides on-demand
+ # thread/process naming for ftrace data below.
+ process_stats_config {
+ scan_all_processes_on_start: true
+ }
+ }
+}
+
+data_sources: {
+ config {
+ name: "linux.ftrace"
+ ftrace_config {
+ ftrace_events: "ftrace/print"
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ atrace_categories: "ss"
+ atrace_categories: "wm"
+ atrace_categories: "am"
+ atrace_categories: "aidl"
+ atrace_categories: "input"
+ atrace_categories: "binder_driver"
+ atrace_categories: "sched_process_exit"
+ atrace_apps: "com.android.server.wm.flicker"
+ atrace_apps: "com.android.server.wm.flicker.other"
+ atrace_apps: "com.android.server.wm.flicker.close"
+ atrace_apps: "com.android.server.wm.flicker.ime"
+ atrace_apps: "com.android.server.wm.flicker.launch"
+ atrace_apps: "com.android.server.wm.flicker.quickswitch"
+ atrace_apps: "com.android.server.wm.flicker.rotation"
+ atrace_apps: "com.android.server.wm.flicker.testapp"
+ atrace_apps: "com.android.systemui"
+ atrace_apps: "com.google.android.apps.nexuslauncher"
+ }
+ }
+}
+
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 039bb4e..46745e9 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,7 +11,7 @@
name: "protologtool-lib",
srcs: [
"src/com/android/protolog/tool/**/*.kt",
- ":protolog-common-src",
+ ":protolog-common-no-android-src",
],
static_libs: [
"javaparser",